今天,在Node.js教程翻译的第九部分中,我们将讨论如何处理文件。 特别是,我们将讨论fs和路径模块-文件描述符,文件路径,获取文件信息,读取和写入文件以及使用目录。

在Node.js中使用文件描述符
在与服务器文件系统中的文件进行交互之前,需要获取文件描述符。
可以通过从
fs
模块使用异步
open()
方法打开文件来获取描述符:
const fs = require('fs') fs.open('/Users/flavio/test.txt', 'r', (err, fd) => { //fd - })
请注意,在调用
fs.open()
方法时使用第二个参数
r
。 这是一个标志,告诉系统正在打开文件以供读取。 以下是使用此方法和其他方法时经常使用的一些标志:
r+
-打开文件进行读写。w+
-通过将流指针设置为文件的开头来打开文件以进行读写。 如果该文件不存在,则会创建它。- a-通过将流指针设置为文件末尾来打开要写入的文件。 如果该文件不存在,则会创建它。
a+
-通过将流指针设置为文件末尾来打开文件以进行读写。 如果该文件不存在,则会创建它。
可以使用同步方法
fs.openSync()
打开文件,而不是在回调中提供文件描述符,而是返回该文件:
const fs = require('fs') try { const fd = fs.openSync('/Users/flavio/test.txt', 'r') } catch (err) { console.error(err) }
使用上述任何一种方法接收描述符后,您可以对其执行必要的操作。
档案资料
每个文件都有一个与之关联的数据集;您可以使用Node.js检查此数据。 特别是,可以使用
fs
模块中的
stat()
方法完成此操作。
调用此方法,将其传递到文件的路径,然后在Node.js收到有关文件的必要信息后,它将调用传递给
stat()
方法的回调。 看起来是这样的:
const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) { console.error(err) return } // `stats` })
Node.js能够同步检索文件信息。 使用这种方法,主线程被阻塞,直到获得文件的属性为止:
const fs = require('fs') try { const stats = fs.statSync ('/Users/flavio/test.txt') } catch (err) { console.error(err) }
有关文件的信息将归入
stats
常量。 这是什么信息? 实际上,相应的对象为我们提供了大量有用的属性和方法:
.isFile()
和.isDirectory()
方法分别允许找出所调查的文件是常规文件还是目录。.isSymbolicLink()
方法可让您知道文件是否是符号链接。- 可以使用
.size
属性找到文件大小。
这里还有其他方法,但是最常用。 使用方法如下:
const fs = require('fs') fs.stat('/Users/flavio/test.txt', (err, stats) => { if (err) { console.error(err) return } stats.isFile() //true stats.isDirectory() //false stats.isSymbolicLink() //false stats.size //1024000 //= 1MB })
Node.js和路径模块中的文件路径
文件路径是文件系统中文件所在位置的地址。
在Linux和macOS上,路径可能如下所示:
/users/flavio/file.txt
在Windows上,路径看起来有些不同:
C:\users\flavio\file.txt
考虑到用于部署Node.js服务器的操作系统,应注意使用不同操作系统时路径记录格式的差异。
Node.js具有设计用于文件路径的标准
path
模块。 在程序中使用此模块之前,必须将其连接:
const path = require('path')
file获取文件路径信息
如果您有文件的路径,则可以使用
path
模块的功能,以方便感知和进一步处理的形式,找到有关此路径的详细信息。 看起来像这样:
const notes = '/users/flavio/notes.txt' path.dirname(notes) // /users/flavio path.basename(notes) // notes.txt path.extname(notes) // .txt
此处,在
notes
行中,存储了文件路径。
path
模块的以下方法用于解析
path
:
dirname()
-返回文件的父目录。basename()
-返回文件名。extname()
-返回文件扩展名。
您可以通过调用
.basename()
方法并向其传递代表扩展名的第二个参数来找出不带扩展名的文件名:
path.basename(notes, path.extname(notes)) //notes
file使用文件路径
可以使用
path.join()
方法将路径的几个部分组合起来:
const name = 'flavio' path.join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt'
您可以使用
path.resolve()
方法根据相对路径找到文件的绝对路径:
path.resolve('flavio.txt') //'/Users/flavio/flavio.txt'
在这种情况下,Node.js只需将
/flavio.txt
添加到通向当前工作目录的路径。 如果在调用此方法时传递了另一个表示文件夹路径的参数,则该方法将其用作确定绝对路径的基础:
path.resolve('tmp', 'flavio.txt') // '/Users/flavio/tmp/flavio.txt'
如果作为第一个参数传递的路径以斜杠开头,则表示它是绝对路径。
path.resolve('/etc', 'flavio.txt') // '/etc/flavio.txt'
这是另一个有用的方法
path.normalize()
。 它允许您使用包含相对路径限定符(例如点(
.
),两点(
..
)或两个斜杠)的路径来查找文件的真实路径:
path.normalize('/users/flavio/..//test.txt')
resolve()
和
normalize()
方法不检查目录是否存在。 他们只是根据传递给他们的数据找到路径。
在Node.js中读取文件
在Node.js中读取文件的最简单方法是使用
fs.readFile()
方法,
fs.readFile()
传递文件路径和回调,这将在文件数据(或错误对象)向其传输时被调用:
fs.readFile('/Users/flavio/test.txt', (err, data) => { if (err) { console.error(err) return } console.log(data) })
如有必要,可以使用此方法的同步版本
fs.readFileSync()
:
const fs = require('fs') try { const data = fs.readFileSync('/Users/flavio/test.txt') console.log(data) } catch (err) { console.error(err) }
默认情况下,读取文件时使用
utf8
编码,但是也可以通过将适当的参数传递给方法来独立设置编码。
fs.readFile()
和
fs.readFileSync()
方法将文件的全部内容读入内存。 这意味着使用这些方法处理大文件将严重影响应用程序的内存消耗并影响其性能。 如果您需要使用此类文件,则最好使用流。
将文件写入Node.js
在Node.js中,使用
fs.writeFile()
方法写入文件最简单:
const fs = require('fs') const content = 'Some content!' fs.writeFile('/Users/flavio/test.txt', content, (err) => { if (err) { console.error(err) return }
相同方法还有一个同步版本
fs.writeFileSync()
:
const fs = require('fs') const content = 'Some content!' try { const data = fs.writeFileSync('/Users/flavio/test.txt', content)
默认情况下,这些方法将替换现有文件的内容。 您可以使用适当的标志来更改其标准行为:
fs.writeFile('/Users/flavio/test.txt', content, { flag: 'a+' }, (err) => {})
可以在这里使用标志,我们已经在描述符部分列出了标志。 关于标志的详细信息可以在
这里找到。
将数据附加到文件
fs.appendFile()
方法(及其同步版本
fs.appendFileSync()
)可方便地用于将数据附加到文件末尾:
const content = 'Some content!' fs.appendFile('file.log', content, (err) => { if (err) { console.error(err) return } //! })
关于使用线程
上面,我们描述了以下方法:在写入文件时,写入传输到该文件的全部数据,然后,如果使用了它们的同步版本,则它们将控制权返回给程序,如果使用了异步版本,则它们将调用回调。 如果这种情况不适合您,则最好使用流。
在Node.js中使用目录
fs
模块为开发人员提供了许多可用于处理目录的便捷方法。
folder检查文件夹是否存在
为了检查目录是否存在以及在给定权限的情况下Node.js是否可以访问它,可以使用
fs.access()
方法。
▍创建一个新文件夹
为了创建新文件夹,可以使用
fs.mkdir()
和
fs.mkdirSync()
方法:
const fs = require('fs') const folderName = '/Users/flavio/test' try { if (!fs.existsSync(dir)){ fs.mkdirSync(dir) } } catch (err) { console.error(err) }
▍读取文件夹的内容
为了读取文件夹的内容,可以使用
fs.readdir()
和
fs.readdirSync()
方法。 本示例读取文件夹的内容,即有关该文件夹包含哪些文件和子目录的信息,并返回它们的相对路径:
const fs = require('fs') const path = require('path') const folderPath = '/Users/flavio' fs.readdirSync(folderPath)
这样可以获取文件的完整路径:
fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName) }
可以对结果进行过滤,以便仅获取文件,并从目录的输出中排除:
const isFile = fileName => { return fs.lstatSync(fileName).isFile() } fs.readdirSync(folderPath).map(fileName => { return path.join(folderPath, fileName)).filter(isFile) }
▍重命名文件夹
您可以使用
fs.rename()
和
fs.renameSync()
方法来重命名文件夹。 第一个参数是当前文件夹路径,第二个参数是新的:
const fs = require('fs') fs.rename('/Users/flavio', '/Users/roger', (err) => { if (err) { console.error(err) return } // })
您可以使用同步方法
fs.renameSync()
重命名文件夹:
const fs = require('fs') try { fs.renameSync('/Users/flavio', '/Users/roger') } catch (err) { console.error(err) }
▍删除文件夹
要删除文件夹,可以使用
fs.rmdir()
或
fs.rmdirSync()
方法。 应当注意,删除其中包含某些内容的文件夹比删除空文件夹要复杂得多。 如果您需要删除此类文件夹,请使用
fs-extra程序包,该程序包非常受欢迎且受支持。 它替代了
fs
模块,从而扩展了其功能。
fs-extra
软件包中的
remove()
方法可以删除已经包含某些内容的文件夹。
您可以按以下方式安装此模块:
npm install fs-extra
这是一个用法示例:
const fs = require('fs-extra') const folder = '/Users/flavio' fs.remove(folder, err => { console.error(err) })
它的方法可以以promise的形式使用:
fs.remove(folder).then(() => { // }).catch(err => { console.error(err) })
async / await构造也是可以接受的:
async function removeFolder(folder) { try { await fs.remove(folder) // } catch (err) { console.error(err) } } const folder = '/Users/flavio' removeFolder(folder)
FS模块
上面,我们已经遇到了使用
fs
模块的一些方法,这些方法在使用文件系统时使用。 实际上,它包含更多有用的东西。 回想一下,它不需要安装,为了在程序中使用它,将其连接就足够了:
const fs = require('fs')
之后,您将可以访问他的方法,其中我们注意到以下内容,其中一些您已经知道:
fs.access()
:检查文件是否存在以及是否基于权限访问文件。fs.appendFile()
: fs.appendFile()
数据fs.appendFile()
到文件。 如果文件不存在,将创建它。fs.chmod()
:更改给定文件的权限。 相似方法: fs.lchmod()
, fs.fchmod()
。fs.chown()
:更改给定文件的所有者和组。 相似方法: fs.fchown()
, fs.lchown()
。fs.close()
:关闭文件描述符。fs.copyFile()
:复制文件。fs.createReadStream()
:创建一个流以读取文件。fs.createWriteStream()
:创建文件写入流。fs.link()
:创建一个指向文件的新硬链接。fs.mkdir()
:创建一个新目录。fs.mkdtemp()
:创建一个临时目录。fs.open()
:打开一个文件。fs.readdir()
:读取目录的内容。fs.readFile()
:读取文件的内容。 相似的方法: fs.read()
。fs.readlink()
:读取符号链接的值。fs.realpath()
:解析使用character构造的相对文件路径.
和..
,完整路径。fs.rename()
:重命名文件或文件夹。fs.rmdir()
:删除文件夹。fs.stat()
:返回文件信息。 相似的方法: fs.fstat()
, fs.lstat()
。fs.symlink()
:创建到文件的新符号链接。fs.truncate()
:将文件截断为指定的长度。 相似的方法: fs.ftruncate()
。fs.unlink()
:删除文件或符号链接。fs.unwatchFile()
:禁用文件更改监视。fs.utimes()
:更改文件的时间戳。 相似方法: fs.futimes()
。fs.watchFile()
:启用监视文件更改。 相似方法: fs.watch()
。fs.writeFile()
:将数据写入文件。 相似的方法: fs.write()
。
fs
模块的一个有趣的功能是,默认情况下,其所有方法都是异步的,但它们也有同步版本,其名称是通过在异步方法的名称上加上
Sync
来获得的。
例如:
fs.rename()
fs.renameSync()
fs.write()
fs.writeSync()
使用同步方法会严重影响程序的工作方式。
Node.js 10为这些基于承诺的API提供了实验性支持。
探索
fs.rename()
方法。 这是使用回调的此方法的异步版本:
const fs = require('fs') fs.rename('before.json', 'after.json', (err) => { if (err) { return console.error(err) } // })
当使用其同步版本时,
try/catch
构造用于处理错误:
const fs = require('fs') try { fs.renameSync('before.json', 'after.json')
使用此方法的这些选项之间的主要区别在于,在第二种情况下,脚本将被阻止,直到文件操作完成为止。
路径模块
我们还谈到了路径模块的某些功能,其中包含许多有用的工具,可让您与文件系统进行交互。 如前所述,您无需安装它,因为它是Node.js的一部分。 为了使用它,连接它就足够了:
const path = require('path')
此模块的
path.sep
属性提供用于分隔路径段的字符(在Windows上为
\
,在Linux和macOS上为
/
),而
path.delimiter
属性提供用于分隔多个路径的字符(在Windows和Linux上为;和macOS)。
让我们考虑并说明
path
模块的一些方法。
▍path.basename()
返回路径的最后一个片段。 通过将第二个参数传递给此方法,可以删除文件扩展名。
require('path').basename('/test/something') //something require('path').basename('/test/something.txt') //something.txt require('path').basename('/test/something.txt', '.txt') //something
▍path.dirname()
返回代表目录名称的路径部分:
require('path').dirname('/test/something') // /test require('path').dirname('/test/something/file.txt') // /test/something
▍path.extname()
返回代表文件扩展名的路径部分:
require('path').extname('/test/something') // '' require('path').extname('/test/something/file.txt') // '.txt'
▍path.isAbsolute()
如果path是绝对的,则返回true:
require('path').isAbsolute('/test/something') // true require('path').isAbsolute('./test/something') // false
▍path.join()
连接路径的几个部分:
const name = 'flavio' require('path').join('/', 'users', name, 'notes.txt') //'/users/flavio/notes.txt'
▍path.normalize()
尝试根据包含用于构建相对路径的字符的路径找出真实路径,例如
.
,
..
和
//
:
require('path').normalize('/users/flavio/..//test.txt')
▍path.parse()
将路径转换为对象,该对象的属性表示路径的各个部分:
root
:根目录。dir
:从根目录开始的文件路径base
:文件名和扩展名。name
:文件名。ext
:文件扩展名。
这是使用此方法的示例:
require('path').parse('/users/test.txt')
通过他的工作,获得了一个对象:
{ root: '/', dir: '/users', base: 'test.txt', ext: '.txt', name: 'test' }
▍path.relative()
以两种方式作为参数。 根据当前工作目录返回从第一个路径到第二个路径的相对路径:
require('path').relative('/Users/flavio', '/Users/flavio/test.txt') //'test.txt' require('path').relative('/Users/flavio', '/Users/flavio/something/test.txt') //'something/test.txt'
▍path.resolve()
根据传递给它的相对路径查找绝对路径:
path.resolve('flavio.txt') //'/Users/flavio/flavio.txt' .
总结
今天,我们研究了用于文件系统的Node.js
fs
和
path
模块。 在本系列的下一部分中,我们将讨论
os
,
events
,
http
模块,并讨论在Node.js中使用流和数据库管理系统。
亲爱的读者们! 在Node.js中使用文件系统时,您使用什么npm软件包?
