Node.js v10.16.3 文档


目录

fs(文件系统)#

中英对照提交修改

稳定性: 2 - 稳定

fs 模块提供了一个 API,用于以模仿标准 POSIX 函数的方式与文件系统进行交互。

要使用此模块:

const fs = require('fs');

所有文件系统操作都具有同步和异步的形式。

异步的形式总是将完成回调作为其最后一个参数。 传给完成回调的参数取决于具体方法,但第一个参数始终预留用于异常。 如果操作成功完成,则第一个参数将为 nullundefined

const fs = require('fs');

fs.unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('已成功删除 /tmp/hello');
});

使用同步的操作发生的异常会立即抛出,可以使用 try…catch 处理,也可以允许冒泡。

const fs = require('fs');

try {
  fs.unlinkSync('/tmp/hello');
  console.log('已成功删除 /tmp/hello');
} catch (err) {
  // 处理错误
}

使用异步的方法时无法保证顺序。 因此,以下的操作容易出错,因为 fs.stat() 操作可能在 fs.rename() 操作之前完成:

fs.rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  console.log('重命名完成');
});
fs.stat('/tmp/world', (err, stats) => {
  if (err) throw err;
  console.log(`文件属性: ${JSON.stringify(stats)}`);
});

要正确地排序这些操作,则将 fs.stat() 调用移动到 fs.rename() 操作的回调中:

fs.rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  fs.stat('/tmp/world', (err, stats) => {
    if (err) throw err;
    console.log(`文件属性: ${JSON.stringify(stats)}`);
  });
});

在繁忙的进程中,强烈建议使用这些调用的异步版本。 同步的版本将阻塞整个进程,直到它们完成(停止所有连接)。

虽然不推荐这样使用,但大多数 fs 函数允许省略回调参数,在这种情况下,使用一个会重新抛出错误的默认回调。 要获取原始调用点的跟踪,则设置 NODE_DEBUG 环境变量:

不推荐在异步的 fs 函数上省略回调函数,因为可能导致将来抛出错误。

$ cat script.js
function bad() {
  require('fs').readFile('/');
}
bad();

$ env NODE_DEBUG=fs node script.js
fs.js:88
        throw backtrace;
        ^
Error: EISDIR: illegal operation on a directory, read
    <stack trace.>

文件路径#

中英对照提交修改

大多数 fs 操作接受的文件路径可以指定为字符串、Buffer、或使用 file: 协议的 URL 对象。

字符串形式的路径被解析为标识绝对或相对文件名的 UTF-8 字符序列。 相对路径将相对于 process.cwd() 指定的当前工作目录进行解析。

在 POSIX 上使用绝对路径的示例:

const fs = require('fs');

fs.open('/open/some/file.txt', 'r', (err, fd) => {
  if (err) throw err;
  fs.close(fd, (err) => {
    if (err) throw err;
  });
});

在 POSIX 上使用相对路径(相对于 process.cwd())的示例:

fs.open('file.txt', 'r', (err, fd) => {
  if (err) throw err;
  fs.close(fd, (err) => {
    if (err) throw err;
  });
});

使用 Buffer 指定的路径主要用于将文件路径视为不透明字节序列的某些 POSIX 操作系统。 在这样的系统上,单个文件路径可以包含使用多种字符编码的子序列。 与字符串路径一样, Buffer 路径可以是相对路径或绝对路径:

在 POSIX 上使用绝对路径的示例:

fs.open(Buffer.from('/open/some/file.txt'), 'r', (err, fd) => {
  if (err) throw err;
  fs.close(fd, (err) => {
    if (err) throw err;
  });
});

在 Windows 上,Node.js 遵循每个驱动器工作目录的概念。 当使用没有反斜杠的驱动器路径时,可以观察到此行为。 例如, fs.readdirSync('c:\\') 可能会返回与 fs.readdirSync('c:') 不同的结果。 有关详细信息,参阅此 MSDN 页面

URL 对象的支持#

中英对照提交修改

对于大多数 fs 模块的函数, pathfilename 参数可以传入 WHATWG URL 对象。 仅支持使用 file: 协议的 URL 对象。

const fs = require('fs');
const fileUrl = new URL('file:///tmp/hello');

fs.readFileSync(fileUrl);

file: URL 始终是绝对路径。

使用 WHATWG URL 对象可能会采用特定于平台的行为。

在 Windows 上,带有主机名的 file: URL 转换为 UNC 路径,而带有驱动器号的 file: URL 转换为本地绝对路径。 没有主机名和驱动器号的 file: URL 将导致抛出错误:

// 在 Windows 上:

// - 带有主机名的 WHATWG 文件的 URL 转换为 UNC 路径。
// file://hostname/p/a/t/h/file => \\hostname\p\a\t\h\file
fs.readFileSync(new URL('file://hostname/p/a/t/h/file'));

// - 带有驱动器号的 WHATWG 文件的 URL 转换为绝对路径。
// file:///C:/tmp/hello => C:\tmp\hello
fs.readFileSync(new URL('file:///C:/tmp/hello'));

// - 没有主机名的 WHATWG 文件的 URL 必须包含驱动器号。
fs.readFileSync(new URL('file:///notdriveletter/p/a/t/h/file'));
fs.readFileSync(new URL('file:///c/p/a/t/h/file'));
// TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute

带有驱动器号的 file: URL 必须使用 : 作为驱动器号后面的分隔符。 使用其他分隔符将导致抛出错误。

在所有其他平台上,不支持带有主机名的 file: URL,使用时将导致抛出错误:

// 在其他平台上:

// - 不支持带有主机名的 WHATWG 文件的 URL。
// file://hostname/p/a/t/h/file => throw!
fs.readFileSync(new URL('file://hostname/p/a/t/h/file'));
// TypeError [ERR_INVALID_FILE_URL_PATH]: must be absolute

// - WHATWG 文件的 URL 转换为绝对路径。
// file:///tmp/hello => /tmp/hello
fs.readFileSync(new URL('file:///tmp/hello'));

包含编码后的斜杆字符(%2F)的 file: URL 在所有平台上都将导致抛出错误:

// 在 Windows 上:
fs.readFileSync(new URL('file:///C:/p/a/t/h/%2F'));
fs.readFileSync(new URL('file:///C:/p/a/t/h/%2f'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
\ or / characters */

// 在 POSIX 上:
fs.readFileSync(new URL('file:///p/a/t/h/%2F'));
fs.readFileSync(new URL('file:///p/a/t/h/%2f'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
/ characters */

在 Windows 上,包含编码后的反斜杆字符(%5C)的 file: URL 将导致抛出错误:

// 在 Windows 上:
fs.readFileSync(new URL('file:///C:/path/%5C'));
fs.readFileSync(new URL('file:///C:/path/%5c'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
\ or / characters */

文件描述符#

中英对照提交修改

在 POSIX 系统上,对于每个进程,内核都维护着一张当前打开着的文件和资源的表格。 每个打开的文件都分配了一个称为文件描述符的简单的数字标识符。 在系统层,所有文件系统操作都使用这些文件描述符来标识和跟踪每个特定的文件。 Windows 系统使用了一个虽然不同但概念上类似的机制来跟踪资源。 为了简化用户的工作,Node.js 抽象出操作系统之间的特定差异,并为所有打开的文件分配一个数字型的文件描述符。

fs.open() 方法用于分配新的文件描述符。 一旦被分配,则文件描述符可用于从文件读取数据、向文件写入数据、或请求关于文件的信息。

fs.open('/open/some/file.txt', 'r', (err, fd) => {
  if (err) throw err;
  fs.fstat(fd, (err, stat) => {
    if (err) throw err;
    // 使用文件属性。

    // 始终关闭文件描述符!
    fs.close(fd, (err) => {
      if (err) throw err;
    });
  });
});

大多数操作系统限制在任何给定时间内可能打开的文件描述符的数量,因此当操作完成时关闭描述符至关重要。 如果不这样做将导致内存泄漏,最终导致应用程序崩溃。

线程池的使用#

中英对照提交修改

所有的文件系统 API,除了 fs.FSWatcher() 和那些显式同步的之外,都使用 libuv 的线程池,这对某些应用程序可能会产生意外和负面的性能影响。 有关更多信息,参阅 UV_THREADPOOL_SIZE 文档。

fs.Dirent 类#

中英对照提交修改

当使用 withFileTypes 选项设置为 true 调用 fs.readdir()fs.readdirSync() 时,生成的数组将填充 fs.Dirent 对象,而不是字符串或 Buffer

dirent.isBlockDevice()#

中英对照提交修改

如果 fs.Dirent 对象描述块设备,则返回 true

dirent.isCharacterDevice()#

中英对照提交修改

如果 fs.Dirent 对象描述字符设备,则返回 true

dirent.isDirectory()#

中英对照提交修改

如果 fs.Dirent 对象描述文件系统目录,则返回 true

dirent.isFIFO()#

中英对照提交修改

如果 fs.Dirent 对象描述先进先出(FIFO)管道,则返回 true

dirent.isFile()#

中英对照提交修改

如果 fs.Dirent 对象描述常规文件,则返回 true

dirent.isSocket()#

中英对照提交修改

如果 fs.Dirent 对象描述套接字,则返回 true

dirent.isSymbolicLink()#

中英对照提交修改

如果 fs.Dirent 对象描述符号链接,则返回 true

dirent.name#

中英对照提交修改

fs.Dirent 对象指向的文件名。 此值的类型取决于传递给 fs.readdir()fs.readdirSync()options.encoding

fs.FSWatcher 类#

中英对照提交修改

成功调用 fs.watch() 方法将返回一个新的 fs.FSWatcher 对象。

所有 fs.FSWatcher 对象都是 EventEmitter 的实例,每当修改指定监视的文件,就会触发 'change' 事件。

'change' 事件#

中英对照提交修改

  • eventType <string> 已发生的更改事件的类型。
  • filename <string> | <Buffer> 更改的文件名(如果相关或可用)。

当监视的目录或文件中发生更改时触发。 在 fs.watch() 中查看更多详细信息。

可能不提供 filename 参数,这取决于操作系统的支持。 如果提供了 filename,则当调用 fs.watch() 并将其 encoding 选项设置为 'buffer' 时, filename 将是一个 Buffer,否则 filename 将是 UTF-8 字符串。

// 使用 fs.watch()监听器的示例。
fs.watch('./tmp', { encoding: 'buffer' }, (eventType, filename) => {
  if (filename) {
    console.log(filename);
    // 打印: <Buffer ...>
  }
});

'close' 事件#

中英对照提交修改

当监视器停止监视更改时触发。 关闭的 fs.FSWatcher 对象在事件处理函数中不再可用。

'error' 事件#

中英对照提交修改

当监视文件时发生错误时触发。 发生错误的 fs.FSWatcher 对象在事件处理函数中不再可用。

watcher.close()#

中英对照提交修改

给定的 fs.FSWatcher 停止监视更改。 一旦停止,则 fs.FSWatcher 对象将不再可用。

fs.ReadStream 类#

中英对照提交修改

成功调用 fs.createReadStream() 将返回一个新的 fs.ReadStream 对象。

所有 fs.ReadStream 对象都是可读流

'close' 事件#

中英对照提交修改

fs.ReadStream 的底层文件描述符已关闭时触发。

'open' 事件#

中英对照提交修改

  • fd <integer> ReadStream 使用的整数型文件描述符。

fs.ReadStream 的文件描述符打开时触发。

'ready' 事件#

中英对照提交修改

fs.ReadStream 准备好使用时触发。

'open' 事件之后立即触发。

readStream.bytesRead#

中英对照提交修改

到目前为止已读取的字节数。

readStream.path#

中英对照提交修改

流正在读取的文件的路径,由 fs.createReadStream() 的第一个参数指定。 如果 path 传入字符串,则 readStream.path 将是字符串。 如果 path 传入 Buffer,则 readStream.path 将是 Buffer

readStream.pending#

中英对照提交修改

如果底层的文件还未被打开(即在触发 'ready' 事件之前),则此属性为 true

fs.Stats 类#

中英对照提交修改

fs.Stats 对象提供有关文件的信息。

fs.stat()fs.lstat()fs.fstat() 及其同步方法返回的对象都属于此类型。 如果传给这些方法的 options 中的 bigint 为 true,则数值将为 bigint 型而不是 number 型。

Stats {
  dev: 2114,
  ino: 48064969,
  mode: 33188,
  nlink: 1,
  uid: 85,
  gid: 100,
  rdev: 0,
  size: 527,
  blksize: 4096,
  blocks: 8,
  atimeMs: 1318289051000.1,
  mtimeMs: 1318289051000.1,
  ctimeMs: 1318289051000.1,
  birthtimeMs: 1318289051000.1,
  atime: Mon, 10 Oct 2011 23:24:11 GMT,
  mtime: Mon, 10 Oct 2011 23:24:11 GMT,
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT }

bigint 的版本:

Stats {
  dev: 2114n,
  ino: 48064969n,
  mode: 33188n,
  nlink: 1n,
  uid: 85n,
  gid: 100n,
  rdev: 0n,
  size: 527n,
  blksize: 4096n,
  blocks: 8n,
  atimeMs: 1318289051000n,
  mtimeMs: 1318289051000n,
  ctimeMs: 1318289051000n,
  birthtimeMs: 1318289051000n,
  atime: Mon, 10 Oct 2011 23:24:11 GMT,
  mtime: Mon, 10 Oct 2011 23:24:11 GMT,
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT }

stats.isBlockDevice()#

中英对照提交修改

如果 fs.Stats 对象描述块设备,则返回 true

stats.isCharacterDevice()#

中英对照提交修改

如果 fs.Stats 对象描述字符设备,则返回 true

stats.isDirectory()#

中英对照提交修改

如果 fs.Stats 对象描述文件系统目录,则返回 true

stats.isFIFO()#

中英对照提交修改

如果 fs.Stats 对象描述先进先出(FIFO)管道,则返回 true

stats.isFile()#

中英对照提交修改

如果 fs.Stats 对象描述常规文件,则返回 true

stats.isSocket()#

中英对照提交修改

如果 fs.Stats 对象描述套接字,则返回 true

stats.isSymbolicLink()#

中英对照提交修改

如果 fs.Stats 对象描述符号链接,则返回 true

此方法仅在使用 fs.lstat() 时有效。

stats.dev#

中英对照提交修改

包含该文件的设备的数字标识符。

stats.ino#

中英对照提交修改

文件系统特定的文件索引节点编号。

stats.mode#

中英对照提交修改

描述文件类型和模式的位字段。

stats.nlink#

中英对照提交修改

文件存在的硬链接数。

stats.uid#

中英对照提交修改

拥有该文件(POSIX)的用户的数字型用户标识符。

stats.gid#

中英对照提交修改

拥有该文件(POSIX)的群组的数字型群组标识符。

stats.rdev#

中英对照提交修改

如果文件被视为特殊文件,则此值为数字型设备标识符。

stats.size#

中英对照提交修改

文件的大小(以字节为单位)。

stats.blksize#

中英对照提交修改

用于 I/O 操作的文件系统块的大小。

stats.blocks#

中英对照提交修改

为此文件分配的块数。

stats.atimeMs#

中英对照提交修改

表明上次访问此文件的时间戳,以 POSIX 纪元以来的毫秒数表示。

stats.mtimeMs#

中英对照提交修改

表明上次修改此文件的时间戳,以 POSIX 纪元以来的毫秒数表示。

stats.ctimeMs#

中英对照提交修改

表明上次更改文件状态的时间戳,以 POSIX 纪元以来的毫秒数表示。

stats.birthtimeMs#

中英对照提交修改

表明此文件的创建时间的时间戳,以 POSIX 纪元以来的毫秒数表示。

stats.atime#

中英对照提交修改

表明上次访问此文件的时间戳。

stats.mtime#

中英对照提交修改

表明上次修改此文件的时间戳。

stats.ctime#

中英对照提交修改

表明上次更改文件状态的时间戳。

stats.birthtime#

中英对照提交修改

表示此文件的创建时间的时间戳。

文件属性的时间值#

中英对照提交修改

atimeMsmtimeMsctimeMsbirthtimeMs 属性是保存相应时间(以毫秒为单位)的数值。 它们的精度取决于平台。 atimemtimectimebirthtime 是对应时间的 Date 对象。 Date 值和数值没有关联性。 赋值新的数值、或者改变 Date 值,都不会影响到对应的属性。

stat 对象中的时间具有以下语义:

  • atime "访问时间" - 上次访问文件数据的时间。由 mknod(2)utimes(2)read(2) 系统调用更改。
  • mtime "修改时间" - 上次修改文件数据的时间。由 mknod(2)utimes(2)write(2) 系统调用更改。
  • ctime "更改时间" - 上次更改文件状态(修改索引节点数据)的时间。由 chmod(2)chown(2)link(2)mknod(2)rename(2)unlink(2)utimes(2)read(2)write(2) 系统调用更改。
  • birthtime "创建时间" - 创建文件的时间。当创建文件时设置一次。 在不支持创建时间的文件系统上,该字段可能改为保存 ctime1970-01-01T00:00Z(即 Unix 纪元时间戳 0)。 在这种情况下,该值可能大于 atimemtime。 在 Darwin 和其他的 FreeBSD 衍生系统上,也可能使用 utimes(2) 系统调用将 atime 显式地设置为比 birthtime 更早的值。

在 Node.js 0.12 之前, ctime 在 Windows 上保存 birthtime。 从 0.12 开始, ctime 不再是“创建时间”,而在 Unix 系统上则从来都不是。

fs.WriteStream 类#

中英对照提交修改

WriteStream 是一个可写流

'close' 事件#

中英对照提交修改

WriteStream 的底层文件描述符已关闭时触发。

'open' 事件#

中英对照提交修改

  • fd <integer> WriteStream 使用的整数型文件描述符。

WriteStream 的文件打开时触发。

'ready' 事件#

中英对照提交修改

fs.WriteStream 准备好使用时触发。

'open' 事件之后立即触发。

writeStream.bytesWritten#

中英对照提交修改

到目前为止写入的字节数。 不包括仍在排队等待写入的数据。

writeStream.path#

中英对照提交修改

流正在写入的文件的路径,由 fs.createWriteStream() 的第一个参数指定。 如果 path 传入字符串,则 writeStream.path 将是字符串。 如果 path 传入 Buffer,则 writeStream.path 将是 Buffer

writeStream.pending#

中英对照提交修改

如果底层的文件还未被打开(即在触发 'ready' 事件之前),则此属性为 true

fs.access(path[, mode], callback)#

中英对照提交修改

测试用户对 path 指定的文件或目录的权限。 mode 参数是一个可选的整数,指定要执行的可访问性检查。 mode 可选的值参阅文件可访问性的常量。 可以创建由两个或更多个值按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。

最后一个参数 callback 是一个回调函数,调用时将传入可能的错误参数。 如果可访问性检查失败,则错误参数将是 Error 对象。 以下示例检查 package.json 是否存在,以及它是否可读或可写。

const file = 'package.json';

// 检查当前目录中是否存在该文件。
fs.access(file, fs.constants.F_OK, (err) => {
  console.log(`${file} ${err ? '不存在' : '存在'}`);
});

// 检查文件是否可读。
fs.access(file, fs.constants.R_OK, (err) => {
  console.log(`${file} ${err ? '不可读' : '可读'}`);
});

// 检查文件是否可写。
fs.access(file, fs.constants.W_OK, (err) => {
  console.log(`${file} ${err ? '不可写' : '可写'}`);
});

// 检查当前目录中是否存在该文件,以及该文件是否可写。
fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => {
  if (err) {
    console.error(
      `${file} ${err.code === 'ENOENT' ? '不存在' : '只可读'}`);
  } else {
    console.log(`${file} 存在,且它是可写的`);
  }
});

不建议在调用 fs.open()fs.readFile()fs.writeFile() 之前使用 fs.access() 检查文件的可访问性。 这样做会引入竞态条件,因为其他进程可能会在两个调用之间更改文件的状态。 相反,应该直接打开、读取或写入文件,如果文件无法访问则处理引发的错误。

写入(不推荐)

fs.access('myfile', (err) => {
  if (!err) {
    console.error('myfile 已存在');
    return;
  }

  fs.open('myfile', 'wx', (err, fd) => {
    if (err) throw err;
    writeMyData(fd);
  });
});

写入(推荐)

fs.open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile 已存在');
      return;
    }

    throw err;
  }

  writeMyData(fd);
});

读取(不推荐)

fs.access('myfile', (err) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile 不存在');
      return;
    }

    throw err;
  }

  fs.open('myfile', 'r', (err, fd) => {
    if (err) throw err;
    readMyData(fd);
  });
});

读取(推荐)

fs.open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile 不存在');
      return;
    }

    throw err;
  }

  readMyData(fd);
});

上面的“不推荐”示例会先检查可访问性,然后再使用文件。 “推荐”示例则更好,因为它们直接使用文件并处理错误(如果有错误的话)。

通常,仅在不直接使用文件时才检查文件的可访问性,例如当其可访问性是来自其他进程的信号时。

在 Windows 上,目录上的访问控制策略(ACL)可能会限制对文件或目录的访问。 但是, fs.access() 函数不检查 ACL,因此即使 ACL 限制用户读取或写入路径,也可能报告路径是可访问的。

fs.accessSync(path[, mode])#

中英对照提交修改

同步地测试用户对 path 指定的文件或目录的权限。 mode 参数是一个可选的整数,指定要执行的可访问性检查。 mode 可选的值参阅文件可访问性的常量。 可以创建由两个或更多个值按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。

如果可访问性检查失败,则抛出 Error。 否则,该方法将返回 undefined

try {
  fs.accessSync('etc/passwd', fs.constants.R_OK | fs.constants.W_OK);
  console.log('可以读写');
} catch (err) {
  console.error('无权访问');
}

fs.appendFile(path, data[, options], callback)#

中英对照提交修改

异步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 Buffer

fs.appendFile('message.txt', '追加的数据', (err) => {
  if (err) throw err;
  console.log('数据已追加到文件');
});

如果 options 是字符串,则它指定字符编码:

fs.appendFile('message.txt', '追加的数据', 'utf8', callback);

path 可以指定为已打开用于追加(使用 fs.open()fs.openSync())的数字型文件描述符。 文件描述符不会自动关闭。

fs.open('message.txt', 'a', (err, fd) => {
  if (err) throw err;
  fs.appendFile(fd, '追加的数据', 'utf8', (err) => {
    fs.close(fd, (err) => {
      if (err) throw err;
    });
    if (err) throw err;
  });
});

fs.appendFileSync(path, data[, options])#

中英对照提交修改

同步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 Buffer

try {
  fs.appendFileSync('message.txt', '追加的数据');
  console.log('数据已追加到文件');
} catch (err) {
  /* 处理错误 */
}

如果 options 是字符串,则它指定字符编码:

fs.appendFileSync('message.txt', '追加的数据', 'utf8');

path 可以指定为已打开用于追加(使用 fs.open()fs.openSync())的数字型文件描述符。 文件描述符不会自动关闭。

let fd;

try {
  fd = fs.openSync('message.txt', 'a');
  fs.appendFileSync(fd, '追加的数据', 'utf8');
} catch (err) {
  /* 处理错误 */
} finally {
  if (fd !== undefined)
    fs.closeSync(fd);
}

fs.chmod(path, mode, callback)#

中英对照提交修改

异步地更改文件的权限。 除了可能的异常,完成回调没有其他参数。

也可参阅 chmod(2)

fs.chmod('my_file.txt', 0o775, (err) => {
  if (err) throw err;
  console.log('文件 “my_file.txt” 的权限已被更改');
});

文件的模式#

中英对照提交修改

fs.chmod()fs.chmodSync() 方法中使用的 mode 参数是使用以下常量的逻辑或运算创建的数字型位掩码:

常量八进制值说明
fs.constants.S_IRUSR0o400所有者可读
fs.constants.S_IWUSR0o200所有者可写
fs.constants.S_IXUSR0o100所有者可执行或搜索
fs.constants.S_IRGRP0o40群组可读
fs.constants.S_IWGRP0o20群组可写
fs.constants.S_IXGRP0o10群组可执行或搜索
fs.constants.S_IROTH0o4其他人可读
fs.constants.S_IWOTH0o2其他人可写
fs.constants.S_IXOTH0o1其他人可执行或搜索

构造 mode 更简单的方法是使用三个八进制数字的序列( 例如 765)。 最左边的数字(示例中的 7)指定文件所有者的权限。 中间的数字(示例中的 6)指定群组的权限。 最右边的数字(示例中的 5)指定其他人的权限。

数字说明
7可读、可写、可执行
6可读、可写
5可读、可执行
4只读
3可写、可执行
2只写
1只可执行
0没有权限

例如,八进制值 0o765 表示:

  • 所有者可以读取、写入和执行该文件。
  • 群组可以读和写入该文件。
  • 其他人可以读取和执行该文件。

当使用期望的文件模式的原始数字时,任何大于 0o777 的值都可能导致不支持一致的特定于平台的行为。 因此,诸如 S_ISVTXS_ISGIDS_ISUID 之类的常量不会在 fs.constants 中公开。

注意事项:在 Windows 上,只能更改写入权限,并且不会实现群组、所有者或其他人的权限之间的区别。

fs.chmodSync(path, mode)#

中英对照提交修改

有关详细信息,参阅此 API 的异步版本的文档:fs.chmod()

也可参阅 chmod(2)

fs.chown(path, uid, gid, callback)#

中英对照提交修改

异步地更改文件的所有者和群组。 除了可能的异常,完成回调没有其他参数。

也可参阅 chown(2)

fs.chownSync(path, uid, gid)#

中英对照提交修改

同步地更改文件的所有者和群组。 返回 undefined。 这是 fs.chown() 的同步版本。

也可参阅 chown(2)

fs.close(fd, callback)#

中英对照提交修改

异步的 close(2)。 除了可能的异常,完成回调没有其他参数。

fs.closeSync(fd)#

中英对照提交修改

同步的 close(2)。返回 undefined

fs.constants#

中英对照提交修改

返回包含文件系统操作常用常量的对象。 当前定义的特定常量在 FS 常量中描述。

fs.copyFile(src, dest[, flags], callback)#

中英对照提交修改

异步地将 src 拷贝到 dest。 默认情况下,如果 dest 已经存在,则覆盖它。 除了可能的异常,回调函数没有其他参数。 Node.js 不保证拷贝操作的原子性。 如果在打开目标文件用于写入后发生错误,则 Node.js 将尝试删除目标文件。

flags 是一个可选的整数,指定拷贝操作的行为。 可以创建由两个或更多个值按位或组成的掩码(比如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。

  • fs.constants.COPYFILE_EXCL - 如果 dest 已存在,则拷贝操作将失败。
  • fs.constants.COPYFILE_FICLONE - 拷贝操作将尝试创建写时拷贝(copy-on-write)链接。如果平台不支持写时拷贝,则使用后备的拷贝机制。
  • fs.constants.COPYFILE_FICLONE_FORCE - 拷贝操作将尝试创建写时拷贝链接。如果平台不支持写时拷贝,则拷贝操作将失败。
const fs = require('fs');

// 默认情况下将创建或覆盖目标文件。
fs.copyFile('源文件.txt', '目标文件.txt', (err) => {
  if (err) throw err;
  console.log('源文件已拷贝到目标文件');
});

如果第三个参数是数字,则它指定 flags:

const fs = require('fs');
const { COPYFILE_EXCL } = fs.constants;

// 通过使用 COPYFILE_EXCL,如果目标文件存在,则操作将失败。
fs.copyFile('源文件.txt', '目标文件.txt', COPYFILE_EXCL, callback);

fs.copyFileSync(src, dest[, flags])#

中英对照提交修改

同步地将 src 拷贝到 dest。 默认情况下,如果 dest 已经存在,则覆盖它。 返回 undefined。 Node.js 不保证拷贝操作的原子性。 如果在打开目标文件用于写入后发生错误,则 Node.js 将尝试删除目标文件。

flags 是一个可选的整数,指定拷贝操作的行为。 可以创建由两个或更多个值按位或组成的掩码(比如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。

  • fs.constants.COPYFILE_EXCL - 如果 dest 已存在,则拷贝操作将失败。
  • fs.constants.COPYFILE_FICLONE - 拷贝操作将尝试创建写时拷贝(copy-on-write)链接。如果平台不支持写时拷贝,则使用后备的拷贝机制。
  • fs.constants.COPYFILE_FICLONE_FORCE - 拷贝操作将尝试创建写时拷贝链接。如果平台不支持写时拷贝,则拷贝操作将失败。
const fs = require('fs');

// 默认情况下将创建或覆盖目标文件。
fs.copyFileSync('源文件.txt', '目标文件.txt');
console.log('源文件已拷贝到目标文件');

如果第三个参数是数字,则它指定 flags:

const fs = require('fs');
const { COPYFILE_EXCL } = fs.constants;

// 通过使用 COPYFILE_EXCL,如果目标文件存在,则操作将失败。
fs.copyFileSync('源文件.txt', '目标文件.txt', COPYFILE_EXCL);

fs.createReadStream(path[, options])#

中英对照提交修改

与可读流的 16 kb 的默认 highWaterMark 不同,此方法返回的流具有 64 kb 的默认 highWaterMark

options 可以包括 startend 值,以从文件中读取一定范围的字节而不是读取整个文件。 startend 都包含在内并从 0 开始计数,允许的值在 [0, Number.MAX_SAFE_INTEGER] 的范围内。 如果指定了 fd 并且 start 被省略或 undefined,则 fs.createReadStream() 从当前文件位置开始顺序读取。 encoding 可以是 Buffer 接受的任何一种字符编码。

如果指定了 fd,则 ReadStream 将忽略 path 参数并使用指定的文件描述符。 这意味着不会触发 'open' 事件。 fd 必须是阻塞的,非阻塞的 fd 应该传给 net.Socket

如果 fd 指向仅支持阻塞读取的字符设备(例如键盘或声卡),则在数据可用之前,读取操作不会完成。 这可以防止进程退出并且流自然关闭。

const fs = require('fs');
// 从某个字符设备创建一个流。
const stream = fs.createReadStream('/dev/input/event0');
setTimeout(() => {
  stream.close(); // 这可能不会关闭流。
  // 人工标记流末尾,就好像底层资源本身已指示文件结尾一样,允许流关闭。
  // 这不会取消挂起的读取操作,如果存在此类操作,则该过程可能仍无法成功退出,直到完成为止。
  stream.push(null);
  stream.read(0);
}, 100);

如果 autoClosefalse,则即使出现错误,也不会关闭文件描述符。 应用程序负责关闭它并确保没有文件描述符泄漏。 如果 autoClose 设为 true(默认行为),则在 'error''end' 事件时将自动关闭文件描述符。

mode 用于设置文件模式(权限和粘滞位),但仅限于创建文件的情况。

示例,从一个大小为 100 字节的文件中读取最后 10 个字节:

fs.createReadStream('sample.txt', { start: 90, end: 99 });

如果 options 是字符串,则它指定字符编码。

fs.createWriteStream(path[, options])#

中英对照提交修改

options 可以包括一个 start 选项,允许在文件开头之后的某个位置写入数据,允许的值在 [0, Number.MAX_SAFE_INTEGER] 的范围内。 如果要修改文件而不是覆盖它,则 flags 模式需要为 r+ 模式而不是默认的 w 模式。 encoding 可以是 Buffer 接受的任何一种字符编码。

如果 autoClose 设置为 true(默认行为),则在 'error''finish' 事件时文件描述符会自动关闭。 如果 autoClosefalse,则即使出现错误,也不会关闭文件描述符。 应用程序负责关闭它并确保没有文件描述符泄漏。

ReadStream 类似,如果指定了 fd,则 WriteStream 将忽略 path 参数并使用指定的文件描述符。 这意味着不会触发 'open' 事件。 fd 必须是阻塞的,非阻塞的 fd 应该传给 net.Socket

如果 options 是字符串,则它指定字符编码。

fs.exists(path, callback)#

中英对照提交修改

稳定性: 0 - 废弃: 改为使用 fs.stat()fs.access()

通过检查文件系统来测试给定的路径是否存在。 然后调用 callback 并带上参数 truefalse

fs.exists('/etc/passwd', (exists) => {
  console.log(exists ? '存在' : '不存在');
});

此回调的参数与其他 Node.js 回调不一致。 通常,Node.js 回调的第一个参数是 err 参数,后面可选地跟随其他参数。 fs.exists() 的回调只有一个布尔值参数。 这是推荐 fs.access() 代替 fs.exists() 的原因之一。

不建议在调用 fs.open()fs.readFile()fs.writeFile() 之前使用 fs.exists() 检查文件是否存在。 这样做会引入竞态条件,因为其他进程可能会在两次调用之间更改文件的状态。 相反,应该直接打开、读取或写入文件,如果文件不存在则处理引发的错误。

写入(不推荐)

fs.exists('myfile', (exists) => {
  if (exists) {
    console.error('myfile 已存在');
  } else {
    fs.open('myfile', 'wx', (err, fd) => {
      if (err) throw err;
      writeMyData(fd);
    });
  }
});

写入(推荐)

fs.open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile 已存在');
      return;
    }

    throw err;
  }

  writeMyData(fd);
});

读取(不推荐)

fs.exists('myfile', (exists) => {
  if (exists) {
    fs.open('myfile', 'r', (err, fd) => {
      if (err) throw err;
      readMyData(fd);
    });
  } else {
    console.error('myfile 不存在');
  }
});

读取(推荐)

fs.open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile 不存在');
      return;
    }

    throw err;
  }

  readMyData(fd);
});

上面的“不推荐”示例会先检查文件是否存在然后再使用该文件。 “推荐”示例则更好,因为它们直接使用文件并处理错误(如果有错误的话)。

通常,仅在文件不直接使用时才检查文件是否存在,例如当其存在性是来自另一个进程的信号时。

fs.existsSync(path)#

中英对照提交修改

如果路径存在,则返回 true,否则返回 false

有关详细信息,参阅此 API 的异步版本的文档:fs.exists()

虽然 fs.exists() 已废弃,但 fs.existsSync() 不是废弃的。 fs.exists()callback 参数接受与其他 Node.js 回调不一致的参数。 fs.existsSync() 不使用回调。

if (fs.existsSync('/etc/passwd')) {
  console.log('文件已存在');
}

fs.fchmod(fd, mode, callback)#

中英对照提交修改

异步的 fchmod(2)。 除了可能的异常,完成回调没有其他参数。

fs.fchmodSync(fd, mode)#

中英对照提交修改

同步的 fchmod(2)。返回 undefined

fs.fchown(fd, uid, gid, callback)#

中英对照提交修改

异步的 fchown(2)。 除了可能的异常,完成回调没有其他参数。

fs.fchownSync(fd, uid, gid)#

中英对照提交修改

同步的 fchown(2)。返回 undefined

fs.fdatasync(fd, callback)#

中英对照提交修改

异步的 fdatasync(2)。 除了可能的异常,完成回调没有其他参数。

fs.fdatasyncSync(fd)#

中英对照提交修改

同步的 fdatasync(2)。返回 undefined

fs.fstat(fd[, options], callback)#

中英对照提交修改

异步的 fstat(2)。 回调会传入两个参数 (err, stats),其中 statsfs.Stats 对象。 fstat()stat() 相同,除了文件是由文件描述符 fd 指定。

fs.fstatSync(fd[, options])#

中英对照提交修改

同步的 fstat(2)

fs.fsync(fd, callback)#

中英对照提交修改

异步的 fsync(2)。 除了可能的异常,完成回调没有其他参数。

fs.fsyncSync(fd)#

中英对照提交修改

同步的 fsync(2)。返回 undefined

fs.ftruncate(fd[, len], callback)#

中英对照提交修改

异步的 ftruncate(2)。 除了可能的异常,完成回调没有其他参数。

如果文件描述符指向的文件大于 len 个字节,则只有前面 len 个字节会保留在文件中。

例如,以下程序只保留文件的前 4 个字节:

console.log(fs.readFileSync('temp.txt', 'utf8'));
// 打印: Node.js

// 获取要截断的文件的文件描述符。
const fd = fs.openSync('temp.txt', 'r+');

// 将文件截断为前 4 个字节。
fs.ftruncate(fd, 4, (err) => {
  assert.ifError(err);
  console.log(fs.readFileSync('temp.txt', 'utf8'));
});
// 打印: Node

如果文件小于 len 个字节,则会对其进行扩展,并且扩展部分将填充空字节('\0'):

console.log(fs.readFileSync('temp.txt', 'utf8'));
// 打印: Node.js

// 获取要截断的文件的文件描述符。
const fd = fs.openSync('temp.txt', 'r+');

// 将文件截断为前 10 个字节,但实际大小为 7 个字节。
fs.ftruncate(fd, 10, (err) => {
  assert.ifError(err);
  console.log(fs.readFileSync('temp.txt'));
});
// 打印: <Buffer 4e 6f 64 65 2e 6a 73 00 00 00>
// (UTF8 的值为 'Node.js\0\0\0')

最后 3 个字节是空字节('\0'),以补充超出的截断。

fs.ftruncateSync(fd[, len])#

中英对照提交修改

返回 undefined

有关详细信息,请参阅此API的异步版本的文档:fs.ftruncate()

fs.futimes(fd, atime, mtime, callback)#

中英对照提交修改

更改文件描述符指向的对象的文件系统时间戳。 参阅 fs.utimes()

此函数在 7.1 之前的 AIX 版本上不起作用,它将返回 UV_ENOSYS 错误。

fs.futimesSync(fd, atime, mtime)#

中英对照提交修改

fs.futimes() 的同步版本。返回 undefined

fs.lchmod(path, mode, callback)#

中英对照提交修改

异步的 lchmod(2)。 除了可能的异常,完成回调没有其他参数。

仅适用于 macOS。

fs.lchmodSync(path, mode)#

中英对照提交修改

同步的 lchmod(2)。返回 undefined

fs.lchown(path, uid, gid, callback)#

中英对照提交修改

异步的 lchown(2)。 除了可能的异常,完成回调没有其他参数。

fs.lchownSync(path, uid, gid)#

中英对照提交修改

同步的 lchown(2)。返回 undefined

fs.link(existingPath, newPath, callback)#

中英对照提交修改

异步的 link(2)。 除了可能的异常,完成回调没有其他参数。

fs.linkSync(existingPath, newPath)#

中英对照提交修改

同步的 link(2)。返回 undefined

fs.lstat(path[, options], callback)#

中英对照提交修改

异步的 lstat(2)。 回调会传入两个参数 (err, stats),其中 statsfs.Stats 对象。 lstat()stat() 相同,只是如果 path 是符号链接,则查看的是链接自身,而不是它指向的文件。

fs.lstatSync(path[, options])#

中英对照提交修改

同步的 lstat(2)

fs.mkdir(path[, options], callback)#

中英对照提交修改

异步地创建目录。 除了可能的异常,完成回调没有其他参数。

可选的 options 参数可以是指定模式(权限和粘滞位)的整数,也可以是具有 mode 属性和 recursive 属性(指示是否应创建父文件夹)的对象。

// 创建 /tmp/a/apple 目录,无论是否存在 /tmp 和 /tmp/a 目录。
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});

在 Windows 上,在根目录上使用 fs.mkdir() (即使使用递归参数)也会导致错误:

fs.mkdir('/', { recursive: true }, (err) => {
  // => [Error: EPERM: operation not permitted, mkdir 'C:\']
});

也可参阅 mkdir(2)

fs.mkdirSync(path[, options])#

中英对照提交修改

同步地创建目录。 返回 undefinedfs.mkdir() 的同步版本。

也可参阅 mkdir(2)

fs.mkdtemp(prefix[, options], callback)#

中英对照提交修改

创建一个唯一的临时目录。

生成要附加在必需的 prefix 后面的六位随机字符,以创建唯一的临时目录。 由于平台的不一致性,请避免在 prefix 中以 X 字符结尾。 在某些平台上,特别是 BSD,可以返回六个以上的随机字符,并用随机字符替换 prefix 中结尾的 X 字符。

创建的目录路径作为字符串传给回调的第二个参数。

可选的 options 参数可以是指定字符编码的字符串,也可以是具有指定要使用的字符编码的 encoding 属性的对象。

fs.mkdtemp(path.join(os.tmpdir(), '目录-'), (err, folder) => {
  if (err) throw err;
  console.log(folder);
  // 打印: /tmp/目录-itXde2 或 C:\Users\...\AppData\Local\Temp\目录-itXde2
});

fs.mkdtemp() 方法将六位随机选择的字符直接附加到 prefix 字符串。 例如,给定目录 /tmp,如果打算在 /tmp 中创建临时目录,则 prefix 必须在尾部加上特定平台的路径分隔符(require('path').sep)。

// 新的临时目录的父目录。
const tmpDir = os.tmpdir();

// 此用法是错误的:
fs.mkdtemp(tmpDir, (err, folder) => {
  if (err) throw err;
  console.log(folder);
  // 输出类似 `/tmpabc123`。
  // 新的临时目录会被创建在文件系统根目录,而不是在 /tmp 目录中。
});

// 此用法是正确的:
const { sep } = require('path');
fs.mkdtemp(`${tmpDir}${sep}`, (err, folder) => {
  if (err) throw err;
  console.log(folder);
  // 输出类似 `/tmp/abc123`。
  // 新的临时目录会被创建在 /tmp 目录中。
});

fs.mkdtempSync(prefix[, options])#

中英对照提交修改

返回创建的目录路径。

有关详细信息,请参阅此 API 异步版本的文档:fs.mkdtemp()

可选的 options 参数可以是指定字符编码的字符串,也可以是具有指定要使用的字符编码的 encoding 属性的对象。

fs.open(path[, flags[, mode]], callback)#

中英对照提交修改

异步地打开文件。参阅 open(2)

mode 设置文件模式(权限和粘滞位),但仅限于创建文件的情况。 在 Windows 上,只能操作写权限,参阅 fs.chmod()

回调有两个参数 (err, fd)

有些字符 (< > : " / \ | ? *) 在 Windows 上是预留的,参阅命名文件、路径以及命名空间。 在 NTFS 上,如果文件名包含冒号,则 Node.js 将打开文件系统流,参阅此 MSDN 页面

基于 fs.open() 的函数也表现出以上行为,比如 fs.writeFile()fs.readFile() 等。

fs.openSync(path[, flags, mode])#

中英对照提交修改

返回表示文件描述符的整数。

有关详细信息,参阅此 API 的异步版本的文档:fs.open()

fs.read(fd, buffer, offset, length, position, callback)#

中英对照提交修改

fd 指定的文件中读取数据。

buffer 是数据将写入的缓冲区。

offset 是 buffer 中开始写入的偏移量。

length 是一个整数,指定要读取的字节数。

position 参数指定从文件中开始读取的位置。 如果 positionnull,则从当前文件位置读取数据,并更新文件位置。 如果 position 是整数,则文件位置将保持不变。

回调有三个参数 (err, bytesRead, buffer)

如果调用此方法的 util.promisify() 版本,则返回的 Promise 会返回具有 bytesRead 属性和 buffer 属性的 Object

fs.readdir(path[, options], callback)#

中英对照提交修改

异步的 readdir(3)。 读取目录的内容。 回调有两个参数 (err, files),其中 files 是目录中的文件名的数组(不包括 '.''..')。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传给回调的文件名的字符编码。 如果 encoding 设置为 'buffer',则返回的文件名是 Buffer 对象。

如果 options.withFileTypes 设置为 true,则 files 数组将包含 fs.Dirent 对象。

fs.readdirSync(path[, options])#

中英对照提交修改

同步的 readdir(3)

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传给回调的文件名的字符编码。 如果 encoding 设置为 'buffer',则返回的文件名是 Buffer 对象。

如果 options.withFileTypes 设置为 true,则返回的结果将包含 fs.Dirent 对象。

fs.readFile(path[, options], callback)#

中英对照提交修改

异步地读取文件的全部内容。

fs.readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});

回调会传入两个参数 (err, data),其中 data 是文件的内容。

如果没有指定 encoding,则返回原始的 buffer。

如果 options 是字符串,则它指定字符编码:

fs.readFile('/etc/passwd', 'utf8', callback);

path 是目录时, fs.readFile()fs.readFileSync() 的行为是特定于平台的。 在 macOS、Linux 和 Windows 上,将返回错误。 在 FreeBSD 上,将返回目录内容的表示。

// 在 macOS、Linux 和 Windows 上:
fs.readFile('<目录>', (err, data) => {
  // => [Error: EISDIR: illegal operation on a directory, read <目录>]
});

// 在 FreeBSD 上:
fs.readFile('<目录>', (err, data) => {
  // => null, <data>
});

fs.readFile() 函数会缓冲整个文件。 为了最小化内存成本,尽可能通过 fs.createReadStream() 进行流式传输。

文件描述符#

中英对照提交修改

  1. 任何指定的文件描述符都必须支持读取。
  2. 如果将文件描述符指定为 path,则不会自动关闭它。
  3. 读数将从当前位置开始。例如,如果文件已经有内容 'Hello World' 并且使用文件描述符读取了六个字节,则使用相同文件描述符调用 fs.readFile() 将返回 'World' 而不是 'Hello World'

fs.readFileSync(path[, options])#

中英对照提交修改

返回 path 的内容。

有关详细信息,参阅此 API 的异步版本的文档:fs.readFile()

如果指定了 encoding 选项,则此函数返回字符串,否则返回 buffer。

fs.readFile() 类似,当 path 是目录时, fs.readFileSync() 的行为是特定于平台的。

// 在 macOS、Linux 和 Windows 上:
fs.readFileSync('<目录>');
// => [Error: EISDIR: illegal operation on a directory, read <目录>]

// 在 FreeBSD 上:
fs.readFileSync('<目录>'); // => <data>

fs.readlink(path[, options], callback)#

中英对照提交修改

异步的 readlink(2)。 回调会传入两个参数 (err, linkString)

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传递给回调的链接路径的字符编码。 如果 encoding 设置为 'buffer',则返回的链接路径将作为 Buffer 对象传入。

fs.readlinkSync(path[, options])#

中英对照提交修改

同步的 readlink(2)。 返回符号链接的字符串值。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传递给回调的链接路径的字符编码。 如果 encoding 设置为 'buffer',则返回的链接路径将作为 Buffer 对象传入。

fs.readSync(fd, buffer, offset, length, position)#

中英对照提交修改

返回 bytesRead 的数量。

有关详细信息,请参阅此 API 异步版本的文档:fs.read()

fs.realpath(path[, options], callback)#

中英对照提交修改

通过解析 ... 和符号链接异步地计算规范路径名。

规范路径名不一定是唯一的。 硬链接和绑定装载可以通过许多路径名暴露文件系统实体。

此函数的行为类似于 realpath(3),但有一些例外

  1. 在不区分大小写的文件系统上不执行大小写转换。。

  2. 符号链接的最大数量与平台无关,并且通常高于本地 realpath(3) 实现支持的数量。

callback 有两个参数 (err, resolvedPath)。 可以使用 process.cwd 来解析相对路径。

仅支持可转换为 UTF8 字符串的路径。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传递给回调的路径的字符编码。 如果 encoding 设置为 'buffer',则返回的路径将作为 Buffer 对象传入。

如果 path 解析为套接字或管道,则该函数将返回该对象的系统相关名称。

fs.realpath.native(path[, options], callback)#

中英对照提交修改

异步的 realpath(3)

callback 有两个参数 (err, resolvedPath)

仅支持可转换为 UTF8 字符串的路径。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传递给回调的路径的字符编码。 如果 encoding 设置为 'buffer',则返回的路径将作为 Buffer 对象传入。

在 Linux 上,当 Node.js 与 musl libc 链接时,procfs 文件系统必须挂载在 /proc 上才能使此功能正常工作。 Glibc 没有这个限制。

fs.realpathSync(path[, options])#

中英对照提交修改

返回已解析的路径名。

有关详细信息,参阅此 API 的异步版本的文档:fs.realpath()

fs.realpathSync.native(path[, options])#

中英对照提交修改

同步的 realpath(3)

仅支持可转换为 UTF8 字符串的路径。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于传递给回调的路径的字符编码。 如果 encoding 设置为 'buffer',则返回的路径将作为 Buffer 对象传入。

在 Linux 上,当 Node.js 与 musl libc 链接时,procfs 文件系统必须挂载在 /proc 上才能使此功能正常工作。 Glibc 没有这个限制。

fs.rename(oldPath, newPath, callback)#

中英对照提交修改

异步地将 oldPath 上的文件重命名为 newPath 提供的路径名。 如果 newPath 已存在,则覆盖它。 除了可能的异常,完成回调没有其他参数。

也可参阅 rename(2)

fs.rename('旧文件.txt', '新文件.txt', (err) => {
  if (err) throw err;
  console.log('重命名完成');
});

fs.renameSync(oldPath, newPath)#

中英对照提交修改

同步的 rename(2)。返回 undefined

fs.rmdir(path, callback)#

中英对照提交修改

异步的 rmdir(2)。 除了可能的异常,完成回调没有其他参数。

在文件(而不是目录)上使用 fs.rmdir() 会导致在 Windows 上出现 ENOENT 错误、在 POSIX 上出现 ENOTDIR 错误。

fs.rmdirSync(path)#

中英对照提交修改

同步的 rmdir(2)。返回 undefined

在文件(而不是目录)上使用 fs.rmdirSync() 会导致在 Windows 上出现 ENOENT 错误、在 POSIX 上出现 ENOTDIR 错误。

fs.stat(path[, options], callback)#

中英对照提交修改

异步的 stat(2)。 回调有两个参数 (err, stats),其中 stats 是一个 fs.Stats 对象。

如果出现错误,则 err.code 将是常见系统错误之一。

不建议在调用 fs.open()fs.readFile()fs.writeFile() 之前使用 fs.stat() 检查文件是否存在。 而是应该直接打开、读取或写入文件,如果文件不可用则处理引发的错误。

要检查文件是否存在但随后并不对其进行操作,则建议使用 fs.access()

例如,给定以下的文件夹结构:

- txtDir
-- file.txt
- app.js

以下程序将会检查给定路径的统计信息:

const fs = require('fs');

const pathsToCheck = ['./txtDir', './txtDir/file.txt'];

for (let i = 0; i < pathsToCheck.length; i++) {
  fs.stat(pathsToCheck[i], function(err, stats) {
    console.log(stats.isDirectory());
    console.log(stats);
  });
}

得到的输出将会类似于:

true
Stats {
  dev: 16777220,
  mode: 16877,
  nlink: 3,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214262,
  size: 96,
  blocks: 0,
  atimeMs: 1561174653071.963,
  mtimeMs: 1561174614583.3518,
  ctimeMs: 1561174626623.5366,
  birthtimeMs: 1561174126937.2893,
  atime: 2019-06-22T03:37:33.072Z,
  mtime: 2019-06-22T03:36:54.583Z,
  ctime: 2019-06-22T03:37:06.624Z,
  birthtime: 2019-06-22T03:28:46.937Z
}
false
Stats {
  dev: 16777220,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214074,
  size: 8,
  blocks: 8,
  atimeMs: 1561174616618.8555,
  mtimeMs: 1561174614584,
  ctimeMs: 1561174614583.8145,
  birthtimeMs: 1561174007710.7478,
  atime: 2019-06-22T03:36:56.619Z,
  mtime: 2019-06-22T03:36:54.584Z,
  ctime: 2019-06-22T03:36:54.584Z,
  birthtime: 2019-06-22T03:26:47.711Z
}

fs.statSync(path[, options])#

中英对照提交修改

同步的 stat(2)

fs.symlink(target, path[, type], callback)#

中英对照提交修改

异步的 symlink(2)。 除了可能的异常,完成回调没有其他参数。 type 参数仅在 Windows 上可用,在其他平台上会被忽略。 它可以被设置为 'dir''file''junction'。 如果未设置 type 参数,则 Node 将会自动检测 target 的类型并使用 'file''dir'。 如果 target 不存在,则将会使用 'file'。 Windows 上使用 'junction' 要求目标路径是绝对路径。 当使用 'junction' 时, target 参数将自动标准化为绝对路径。

示例:

fs.symlink('./foo', './new-port', callback);

它创建了一个名为 "new-port" 且指向 "foo" 的符号链接。

fs.symlinkSync(target, path[, type])#

中英对照提交修改

返回 undefined

有关详细信息,参阅此 API 的异步版本的文档:fs.symlink()

fs.truncate(path[, len], callback)#

中英对照提交修改

异步的 truncate(2)。 除了可能的异常,完成回调没有其他参数。 文件描述符也可以作为第一个参数传入。 在这种情况下,调用 fs.ftruncate()

不推荐传入文件描述符,可能导致将来抛出错误。

fs.truncateSync(path[, len])#

中英对照提交修改

同步的 truncate(2)。 返回 undefined。 文件描述符也可以作为第一个参数传入。 在这种情况下,调用 fs.ftruncateSync()

不推荐传入文件描述符,可能导致将来抛出错误。

fs.unlink(path, callback)#

中英对照提交修改

异步地删除文件或符号链接。 除了可能的异常,完成回调没有其他参数。

// 假设 'path/file.txt' 是常规文件。
fs.unlink('path/file.txt', (err) => {
  if (err) throw err;
  console.log('文件已删除');
});

fs.unlink() 不能用于目录。 要删除目录,则使用 fs.rmdir()

也可参阅 unlink(2)

fs.unlinkSync(path)#

中英对照提交修改

同步的 unlink(2)。返回 undefined

fs.unwatchFile(filename[, listener])#

中英对照提交修改

停止监视 filename 的变化。 如果指定了 listener,则仅移除此特定监听器,否则,将移除所有监听器,从而停止监视 filename

对未被监视的文件名调用 fs.unwatchFile() 将是空操作,而不是错误。

使用 fs.watch()fs.watchFile()fs.unwatchFile() 更高效。 应尽可能使用 fs.watch() 代替 fs.watchFile()fs.unwatchFile()

fs.utimes(path, atime, mtime, callback)#

中英对照提交修改

更改 path 指向的对象的文件系统时间戳。

atimemtime 参数遵循以下规则:

  • 值可以是表示 Unix 纪元时间的数字、 Date 对象、或类似 '123456789.0' 的数值字符串。
  • 如果该值无法转换为数值、或值为 NaNInfinity-Infinity,则抛出错误。

fs.utimesSync(path, atime, mtime)#

中英对照提交修改

返回 undefined

有关详细信息,参阅此 API 的异步版本的文档:fs.utimes()

fs.watch(filename[, options][, listener])#

中英对照提交修改

监视 filename 的更改,其中 filename 是文件或目录。

第二个参数是可选的。 如果 options 传入字符串,则它指定 encoding。 否则, options 应传入对象。

监听器回调有两个参数 (eventType, filename)eventType'rename''change'filename 是触发事件的文件的名称。

在大多数平台上,每当文件名在目录中出现或消失时,就会触发 'rename' 事件。

监听器回调绑定在由 fs.FSWatcher 触发的 'change' 事件上,但它与 eventType'change' 值不是一回事。

注意事项#

中英对照提交修改

fs.watch 的 API 在各个平台上并非 100% 一致,在某些情况下不可用。

仅在 macOS 和 Windows 上支持 recursive 选项。

可用性#

中英对照提交修改

此特性取决于底层操作系统,提供了一种通知文件系统更改的方法。

如果底层功能由于某些原因不可用,则 fs.watch 将无法运行。 例如,当使用虚拟化软件(如 Vagrant、Docker 等)时,在网络文件系统(NFS、SMB 等)或主文件系统上监视文件或目录可能是不可靠的,在某些情况下也是不可能的。

仍然可以使用 fs.watchFile(),因为它使用 stat 轮询 ,但这种方法较慢且不太可靠。

索引节点#

中英对照提交修改

在 Linux 或 macOS 系统上, fs.watch() 解析路径到索引节点并监视该索引节点。 如果删除并重新创建监视的路径,则会为其分配一个新的索引节点。 监视器会因删除而触发事件,但会继续监视原始的索引节点。 不会因新建索引节点而触发事件。 这是预期的行为。

AIX 文件在文件的生命周期中保留相同的索引节点。 在 AIX 上保存和关闭监视的文件将导致两个通知(一个用于添加新内容,一个用于截断)。

文件名参数#

中英对照提交修改

仅在 Linux、macOS、Windows 和 AIX 上支持在回调中提供 filename 参数。 即使在支持的平台上,也不总是保证提供 filename。 因此,不要假设在回调中始终提供 filename 参数,并且如果它为 null 则需要一些后备逻辑。

fs.watch('somedir', (eventType, filename) => {
  console.log(`事件类型是: ${eventType}`);
  if (filename) {
    console.log(`提供的文件名: ${filename}`);
  } else {
    console.log('文件名未提供');
  }
});

fs.watchFile(filename[, options], listener)#

中英对照提交修改

监视 filename 的更改。 每当访问文件时都会调用 listener 回调。

options 参数可以省略。 如果提供,则它应该是一个对象。 options 对象可以包含一个名为 persistent 的布尔值,指示当文件正在被监视时,进程是否应该继续运行。 options 对象可以指定 interval 属性,指示轮询目标的频率(以毫秒为单位)。

listener 有两个参数,当前的 stat 对象和之前的 stat 对象:

fs.watchFile('message.text', (curr, prev) => {
  console.log(`当前的最近修改时间是: ${curr.mtime}`);
  console.log(`之前的最近修改时间是: ${prev.mtime}`);
});

这些 stat 对象是 fs.Stat 的实例。

要在修改文件(而不仅仅是访问)时收到通知,则需要比较 curr.mtimeprev.mtime

fs.watchFile 操作导致 ENOENT 错误时,它将调用一次监听器,并将所有字段置零(或将日期设为 Unix 纪元)。 如果文件是在那之后创建的,则监听器会被再次调用,且带上最新的 stat 对象。 这是 v0.10 之后的功能变化。

使用 fs.watch()fs.watchFilefs.unwatchFile 更高效。 应尽可能使用 fs.watch 代替 fs.watchFilefs.unwatchFile

fs.watchFile() 正在监视的文件消失并重新出现时,第二次回调事件(文件重新出现)返回的 previousStat 会与第一次回调事件(文件消失)返回的 previousStat 相同。

这种情况发生在:

  • 文件被删除,然后又恢复。
  • 文件被重命名两次,且第二次重命名回其原来的名称。

fs.write(fd, buffer[, offset[, length[, position]]], callback)#

中英对照提交修改

buffer 写入到 fd 指定的文件。

offset 决定 buffer 中要被写入的部位, length 是一个整数,指定要写入的字节数。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 typeof position !== 'number',则数据会被写入当前的位置。 参阅 pwrite(2)

回调有三个参数 (err, bytesWritten, buffer),其中 bytesWritten 指定 buffer 中被写入的字节数。

如果调用此方法的 util.promisify() 版本,则返回的 Promise 会返回具有 bytesWrittenbuffer 属性的 Object

在同一个文件上多次使用 fs.write() 且不等待回调是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

fs.write(fd, string[, position[, encoding]], callback)#

中英对照提交修改

string 写入到 fd 指定的文件。 如果 string 不是一个字符串,则该值会被强制转换为字符串。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 typeof position !== 'number',则数据会被写入当前的位置。 参阅 pwrite(2)

encoding 是期望的字符串编码。

回调会接收到参数 (err, written, string),其中 written 指定传入的字符串中被要求写入的字节数。 被写入的字节数不一定与被写入的字符串字符数相同。 参阅 Buffer.byteLength

在同一个文件上多次使用 fs.write() 且不等待回调是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

在 Windows 上,如果文件描述符连接到控制台(例如 fd == 1stdout),则无论使用何种编码,包含非 ASCII 字符的字符串默认情况下都不会被正确地渲染。 通过使用 chcp 65001 命令更改活动的代码页,可以将控制台配置为正确地渲染 UTF-8。 详见 chcp 文档。

fs.writeFile(file, data[, options], callback)#

中英对照提交修改

file 是一个文件名时,异步地将数据写入到一个文件,如果文件已存在则覆盖该文件。 data 可以是字符串或 buffer。

file 是一个文件描述符时,行为类似于直接调用 fs.write()(建议使用)。 请参阅以下有关使用文件描述符的说明。

如果 data 是一个 buffer,则 encoding 选项会被忽略。

const data = new Uint8Array(Buffer.from('Node.js中文网'));
fs.writeFile('文件.txt', data, (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

如果 options 是一个字符串,则它指定字符编码:

fs.writeFile('文件.txt', 'Node.js中文网', 'utf8', callback);

在同一个文件上多次使用 fs.writeFile() 且不等待回调是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

使用 fs.writeFile() 与文件描述符#

中英对照提交修改

file 是一个文件描述符时,行为几乎与直接调用 fs.write() 类似:

fs.write(fd, Buffer.from(data, options.encoding), callback);

与直接调用 fs.write() 的区别在于,在某些异常情况下, fs.write() 可能只写入部分 buffer,需要重试以写入剩余的数据,而 fs.writeFile() 将会重试直到数据完全写入(或发生错误)。

这种影响是混淆的常见原因。 在文件描述符的情况下,文件不会被替换! 数据不一定写入到文件的开头,文件的原始数据可以保留在新写入的数据之前和/或之后。

例如,如果连续两次调用 fs.writeFile(),首先写入字符串 'Hello',然后写入字符串 ', World',则该文件将会包含 'Hello, World',并且可能包含文件的一些原始数据(取决于原始文件的大小和文件描述符的位置)。 如果使用了文件名而不是描述符,则该文件将会保证仅包含 ', World'

fs.writeFileSync(file, data[, options])#

中英对照提交修改

返回 undefined

有关详细信息,参阅此 API 的异步版本的文档:fs.writeFile()

fs.writeSync(fd, buffer[, offset[, length[, position]]])#

中英对照提交修改

有关详细信息,参阅此 API 的异步版本的文档:fs.write(fd, buffer...)

fs.writeSync(fd, string[, position[, encoding]])#

中英对照提交修改

有关详细信息,参阅此 API 的异步版本的文档: fs.write(fd, string...)

fs.writev(fd, buffers[, position], callback)#

中英对照提交修改

使用 writev() 将一个 ArrayBufferView 数组写入 fd 指定的文件。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 typeof position !== 'number',则数据会被写入当前的位置。

回调有三个参数:errbytesWrittenbuffersbytesWritten 是从 buffers 写入的字节数。

如果此方法是 util.promisify() 化的版本,则它返回的 Promise 会返回具有 bytesWrittenbuffers 属性的 Object

在同一个文件上多次使用 fs.writev() 且不等待回调是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

fs.writevSync(fd, buffers[, position])#

中英对照提交修改

有关详细信息,参阅此 API 的异步版本的文档:fs.writev()

fs 的 Promise API#

中英对照提交修改

fs.promises API 提供了一组备用的异步文件系统的方法,它们返回 Promise 对象而不是使用回调。 API 可通过 require('fs').promises 访问。

FileHandle 类#

中英对照提交修改

FileHandle 对象是数字文件描述符的包装器。 FileHandle 的实例与数字文件描述符的不同之处在于它们提供了一个面向对象的 API 来处理文件。

如果没有使用 filehandle.close() 方法关闭 FileHandle,则它可能会自动关闭文件描述符并触发进程警告,从而有助于防止内存泄漏。 请不要在代码中依赖此行为,因为它不可靠,且你的文件可能无法关闭。 相反,应该始终显式的关闭 FileHandles。 Node.js 将来可能会改变这种行为。

FileHandle 对象的实例由 fsPromises.open() 方法在内部创建。

与基于回调的 API(如 fs.fstat()fs.fchown()fs.fchmod() 等)不同,基于 promise 的 API 不使用数字文件描述符。 而是,基于 promise 的 API 使用 FileHandle 类,以帮助避免在解决或拒绝 Promise 后意外泄漏未关闭的文件描述符。

filehandle.appendFile(data, options)#

中英对照提交修改

异步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 BufferPromise 将会在成功时解决,且不带参数。

如果 options 是字符串,则它指定字符编码。

FileHandle 必须被打开用以追加。

filehandle.chmod(mode)#

中英对照提交修改

更改文件的权限。 Promise 将会在成功时解决,且不带参数。

filehandle.chown(uid, gid)#

中英对照提交修改

更改文件的所有者,然后在成功时解决 Promise 且不带参数。

filehandle.close()#

中英对照提交修改

  • 返回: <Promise> 如果底层的文件描述符被关闭则 Promise 将会被解决,如果关闭时发生错误则将 Promise 将会被拒绝。 关闭文件描述符。
const fsPromises = require('fs').promises;
async function openAndClose() {
  let filehandle;
  try {
    filehandle = await fsPromises.open('thefile.txt', 'r');
  } finally {
    if (filehandle !== undefined)
      await filehandle.close();
  }
}

filehandle.datasync()#

中英对照提交修改

异步的 fdatasync(2)Promise 将会在成功时解决,且不带参数。

filehandle.fd#

中英对照提交修改

  • <number>FileHandle 对象管理的数字文件描述符。

filehandle.read(buffer, offset, length, position)#

中英对照提交修改

从文件中读取数据。

buffer 是数据将写入的缓冲区。

offset 是 buffer 中开始写入的偏移量。

length 是一个整数,指定要读取的字节数。

position 参数指定从文件中开始读取的位置。 如果 positionnull,则从当前文件位置读取数据,并更新文件位置。 如果 position 是整数,则文件位置将保持不变。

成功读取之后, Promise 会被解决并带上一个对象,对象上有一个 bytesRead 属性(指定读取的字节数)和一个 buffer 属性(指向传入的 buffer 参数)。

filehandle.readFile(options)#

中英对照提交修改

异步地读取文件的全部内容。

Promise 被解决时会带上文件的内容。 如果没有指定字符编码(使用 options.encoding),则数据会以 Buffer 对象返回。 否则,数据将会是一个字符串。

如果 options 是字符串,则它指定字符编码。

path 是目录时, fsPromises.readFile() 的行为是特定于平台的。 在 macOS、Linux 和 Windows 上,promise 将会被拒绝并带上一个错误。 在 FreeBSD 上,则将会返回目录内容的表示。

FileHandle 必须支持读取。

如果对文件句柄进行了一次或多次 filehandle.read() 调用,然后再调用 filehandle.readFile(),则将从当前位置读取数据,直到文件结束。 它并不总是从文件的开头读取。

filehandle.stat([options])#

中英对照提交修改

检索文件的 fs.Stats

filehandle.sync()#

中英对照提交修改

异步的 fsync(2)Promise 将会在成功时解决,且不带参数。

filehandle.truncate(len)#

中英对照提交修改

截断文件,然后在成功时解决 Promise 且不带参数。

如果文件大于 len 个字节,则只有前面 len 个字节会保留在文件中。

例如,以下程序只保留文件的前 4 个字节:

const fs = require('fs');
const fsPromises = fs.promises;

console.log(fs.readFileSync('temp.txt', 'utf8'));
// 打印: Node.js

async function doTruncate() {
  let filehandle = null;
  try {
    filehandle = await fsPromises.open('temp.txt', 'r+');
    await filehandle.truncate(4);
  } finally {
    if (filehandle) {
      // 如果文件已打开,则关闭文件。
      await filehandle.close();
    }
  }
  console.log(fs.readFileSync('temp.txt', 'utf8'));  // 打印: Node
}

doTruncate().catch(console.error);

如果文件小于 len 个字节,则会对其进行扩展,并且扩展部分将填充空字节('\0'):

const fs = require('fs');
const fsPromises = fs.promises;

console.log(fs.readFileSync('temp.txt', 'utf8'));
// 打印: Node.js

async function doTruncate() {
  let filehandle = null;
  try {
    filehandle = await fsPromises.open('temp.txt', 'r+');
    await filehandle.truncate(10);
  } finally {
    if (filehandle) {
      // 如果文件已打开,则关闭文件。
      await filehandle.close();
    }
  }
  console.log(fs.readFileSync('temp.txt', 'utf8'));  // 打印 Node.js\0\0\0
}

doTruncate().catch(console.error);

最后 3 个字节是空字节('\0'),以补充超出的截断。

filehandle.utimes(atime, mtime)#

中英对照提交修改

更改 FileHandle 指向的对象的文件系统时间戳,然后在成功时解决 Promise 且不带参数。

此函数在 7.1 之前的 AIX 版本上不起作用,它将会解决 Promise 并带上使用 UV_ENOSYS 代码的错误。

filehandle.write(buffer, offset, length, position)#

中英对照提交修改

buffer 写入到文件。

Promise 会被解决并带上一个对象,对象包含一个 bytesWritten 属性(指定写入的字节数)和一个 buffer 属性(指向写入的 buffer)。

offset 决定 buffer 中要被写入的部位, length 是一个整数,指定要写入的字节数。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 typeof position !== 'number',则数据会被写入当前的位置。 参阅 pwrite(2)

在同一个文件上多次使用 filehandle.write() 且不等待 Promise 被解决(或被拒绝)是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

filehandle.write(string[, position[, encoding]])#

中英对照提交修改

string 写入到文件。 如果 string 不是一个字符串,则该值会被强制转换为字符串。

Promise 会被解决并带上一个对象,对象包含一个 bytesWritten 属性(指定写入的字节数)和一个 buffer 属性(指向写入的 string)。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 position 的类型不是一个 number,则数据会被写入当前的位置。 参阅 pwrite(2)

encoding 是期望的字符串编码。

在同一个文件上多次使用 filehandle.write() 且不等待 Promise 被解决(或被拒绝)是不安全的。 对于这种情况,建议使用 fs.createWriteStream()

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

filehandle.writeFile(data, options)#

中英对照提交修改

异步地将数据写入到一个文件,如果文件已存在则覆盖该文件。 data 可以是字符串或 buffer。 Promise 将会在成功时解决,且不带参数。

如果 data 是一个 buffer,则 encoding 选项会被忽略。

如果 options 是一个字符串,则它指定字符编码。

FileHandle 必须支持写入。

在同一个文件上多次使用 filehandle.writeFile() 且不等待 Promise 被解决(或被拒绝)是不安全的。

如果对文件句柄进行了一次或多次 filehandle.write() 调用,然后再调用 filehandle.writeFile(),则将从当前位置写入数据,直到文件结束。 它并不总是从文件的开头写入。

filehandle.writev(buffers[, position])#

中英对照提交修改

ArrayBufferViews 数组写入该文件。

Promise 会被解决并带上一个对象,对象包含一个 bytesWritten 属性(表明写入的字节数)和一个 buffers 属性(指向 buffers 输入)。

position 指定文件开头的偏移量(数据应该被写入的位置)。 如果 typeof position !== 'number',则数据会被写入当前的位置。

在同一文件上多次调用 writev() 且不等待前面的操作完成,这是不安全的。

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

fsPromises.access(path[, mode])#

中英对照提交修改

测试用户对 path 指定的文件或目录的权限。 mode 参数是一个可选的整数,指定要执行的可访问性检查。 mode 可选的值参阅文件可访问性的常量。 可以创建由两个或更多个值按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。

如果可访问性检查成功,则 Promise 会被解决且不带值。 如果任何可访问性检查失败,则 Promise 会被拒绝并带上 Error 对象。 以下示例会检查当前进程是否可以读取和写入 /etc/passwd 文件。

const fs = require('fs');
const fsPromises = fs.promises;

fsPromises.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK)
  .then(() => console.log('可以访问'))
  .catch(() => console.error('不可访问'));

不建议在调用 fsPromises.open() 之前使用 fsPromises.access() 检查文件的可访问性。 这样做会引入竞态条件,因为其他进程可能会在两个调用之间更改文件的状态。 相反,应该直接打开、读取或写入文件,如果文件无法访问则处理引发的错误。

fsPromises.appendFile(path, data[, options])#

中英对照提交修改

异步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 BufferPromise 将会在成功时解决,且不带参数。

如果 options 是字符串,则它指定字符编码。

path 可以指定为已打开用于追加(使用 fsPromises.open())的 FileHandle

fsPromises.chmod(path, mode)#

中英对照提交修改

更改文件的权限,然后在成功时解决 Promise 且不带参数。

fsPromises.chown(path, uid, gid)#

中英对照提交修改

更改文件的所有者,然后在成功时解决 Promise 且不带参数。

fsPromises.copyFile(src, dest[, flags])#

中英对照提交修改

异步地将 src 拷贝到 dest。 默认情况下,如果 dest 已经存在,则覆盖它。 Promise 将会在成功时解决,且不带参数。

Node.js 不保证拷贝操作的原子性。 如果在打开目标文件用于写入后发生错误,则 Node.js 将尝试删除目标文件。

flags 是一个可选的整数,指定拷贝操作的行为。 可以创建由两个或更多个值按位或组成的掩码(比如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。

  • fs.constants.COPYFILE_EXCL - 如果 dest 已存在,则拷贝操作将失败。
  • fs.constants.COPYFILE_FICLONE - 拷贝操作将尝试创建写时拷贝(copy-on-write)链接。如果平台不支持写时拷贝,则使用后备的拷贝机制。
  • fs.constants.COPYFILE_FICLONE_FORCE - 拷贝操作将尝试创建写时拷贝链接。如果平台不支持写时拷贝,则拷贝操作将失败。
const fsPromises = require('fs').promises;

// 默认情况下将创建或覆盖目标文件。
fsPromises.copyFile('源文件.txt', '目标文件.txt')
  .then(() => console.log('源文件已拷贝到目标文件'))
  .catch(() => console.log('该文件无法拷贝'));

如果第三个参数是数字,则它指定 flags:

const fs = require('fs');
const fsPromises = fs.promises;
const { COPYFILE_EXCL } = fs.constants;

// 通过使用 COPYFILE_EXCL,如果目标文件存在,则操作将失败。
fsPromises.copyFile('源文件.txt', '目标文件.txt', COPYFILE_EXCL)
  .then(() => console.log('源文件已拷贝到目标文件'))
  .catch(() => console.log('该文件无法拷贝'));

fsPromises.lchmod(path, mode)#

中英对照提交修改

更改符号链接的权限,然后在成功时解决 Promise 且不带参数。 此方法仅在 macOS 上实现。

fsPromises.lchown(path, uid, gid)#

中英对照提交修改

更改符号链接的拥有者,然后在成功时解决 Promise 且不带参数。

fsPromises.link(existingPath, newPath)#

中英对照提交修改

异步的 link(2)Promise 将会在成功时解决,且不带参数。

fsPromises.lstat(path[, options])#

中英对照提交修改

异步的 lstat(2)Promise 会被解决并带上用于给定的符号链接 pathfs.Stats 对象。

fsPromises.mkdir(path[, options])#

中英对照提交修改

异步地创建目录,然后在成功时解决 Promise 且不带参数。

可选的 options 参数可以是指定模式(权限和粘滞位)的整数,也可以是具有 mode 属性和 recursive 属性(指示是否应创建父文件夹)的对象。 当 path 是一个已存在的目录时,调用 fsPromises.mkdir() 仅在 recursive 为 false 时才导致拒绝。

fsPromises.mkdtemp(prefix[, options])#

中英对照提交修改

创建一个唯一的临时目录,且解决 Promise 时带上创建的目录路径。 唯一的目录名称是通过在提供的 prefix 的末尾附加六个随机字符来生成的。 由于平台的不一致性,请避免在 prefix 中以 X 字符结尾。 在某些平台上,特别是 BSD,可以返回六个以上的随机字符,并用随机字符替换 prefix 中结尾的 X 字符。

可选的 options 参数可以是指定字符编码的字符串,也可以是具有指定要使用的字符编码的 encoding 属性的对象。

fsPromises.mkdtemp(path.join(os.tmpdir(), 'foo-'))
  .catch(console.error);

fsPromises.mkdtemp() 方法将六位随机选择的字符直接附加到 prefix 字符串。 例如,给定目录 /tmp,如果打算在 /tmp 中创建临时目录,则 prefix 必须在尾部加上特定平台的路径分隔符(require('path').sep)。

fsPromises.open(path, flags[, mode])#

中英对照提交修改

异步地打开文件并返回一个 Promise,当解决时会带上一个 FileHandle 对象。 参阅 open(2)

mode 设置文件模式(权限和粘滞位),但仅限于创建文件的情况。

有些字符 (< > : " / \ | ? *) 在 Windows 上是预留的,参阅命名文件、路径以及命名空间。 在 NTFS 上,如果文件名包含冒号,则 Node.js 将打开文件系统流,参阅此 MSDN 页面

fsPromises.readdir(path[, options])#

中英对照提交修改

读取目录的内容,然后解决 Promise 并带上一个数组(包含目录中的文件的名称,但不包括 '.''..')。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于文件名的字符编码。 如果 encoding 设置为 'buffer',则返回的文件名是 Buffer 对象。

如果 options.withFileTypes 设置为 true,则解决的数组将包含 fs.Dirent 对象。

fsPromises.readFile(path[, options])#

中英对照提交修改

异步地读取文件的全部内容。

Promise 被解决时会带上文件的内容。 如果没有指定字符编码(使用 options.encoding),则数据会以 Buffer 对象返回。 否则,数据将会是一个字符串。

如果 options 是字符串,则它指定字符编码。

path 是目录时, fsPromises.readFile() 的行为是特定于平台的。 在 macOS、Linux 和 Windows 上,promise 将会被拒绝并带上一个错误。 在 FreeBSD 上,则将会返回目录内容的表示。

指定的 FileHandle 必须支持读取。

fsPromises.readlink(path[, options])#

中英对照提交修改

异步的 readlink(2)Promise 会在成功时解决,且带上 linkString

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于链接路径的字符编码。 如果 encoding 设置为 'buffer',则返回的链接路径将作为 Buffer 对象传入。

fsPromises.realpath(path[, options])#

中英对照提交修改

使用与 fs.realpath.native() 函数相同的语义来判断 path 的实际位置,然后解决 Promise 并带上解析后的路径。

仅支持可转换为 UTF8 字符串的路径。

可选的 options 参数可以是指定编码的字符串,也可以是具有 encoding 属性的对象,该属性指定用于路径的字符编码。 如果 encoding 设置为 'buffer',则返回的路径将作为 Buffer 对象传入。

在 Linux 上,当 Node.js 与 musl libc 链接时,procfs 文件系统必须挂载在 /proc 上才能使此功能正常工作。 Glibc 没有这个限制。

fsPromises.rename(oldPath, newPath)#

中英对照提交修改

oldPath 重命名为 newPath,然后在成功时解决 Promise 且不带参数。

fsPromises.rmdir(path)#

中英对照提交修改

删除 path 指定的目录,然后在成功时解决 Promise 且不带参数。

在文件(而不是目录)上使用 fsPromises.rmdir() 会导致 Promise 被拒绝,在 Windows 上会带上 ENOENT 错误,而在 POSIX 上则会带上 ENOTDIR 错误。

fsPromises.stat(path[, options])#

中英对照提交修改

Promise 会被解决并带上 fs.Stats 对象(用于给定的 path)。

fsPromises.symlink(target, path[, type])#

中英对照提交修改

创建一个符号链接,然后在成功时解决 Promise 且不带参数。

type 参数仅在 Windows 上可用,可以是 'dir''file''junction' 之一。 Windows 上使用 'junction' 要求目标路径是绝对路径。 当使用 'junction' 时, target 参数将自动标准化为绝对路径。

fsPromises.truncate(path[, len])#

中英对照提交修改

截断 path,然后在成功时解决 Promise 且不带参数。 path 必须是一个字符串或 Buffer

fsPromises.unlink(path)#

中英对照提交修改

异步的 unlink(2)Promise 将会在成功时解决,且不带参数。

fsPromises.utimes(path, atime, mtime)#

中英对照提交修改

更改 path 指向的对象的文件系统时间戳,然后在成功时解决 Promise 且不带参数。

atimemtime 参数遵循以下规则:

  • 值可以是表示 Unix 纪元时间的数字、 Date 对象、或类似 '123456789.0' 的数值字符串。
  • 如果该值无法转换为数值、或值为 NaNInfinity-Infinity,则抛出 Error

fsPromises.writeFile(file, data[, options])#

中英对照提交修改

异步地将数据写入到一个文件,如果文件已存在则覆盖该文件。 data 可以是字符串或 buffer。 Promise 将会在成功时解决,且不带参数。

如果 data 是一个 buffer,则 encoding 选项会被忽略。

如果 options 是一个字符串,则它指定字符编码。

指定的 FileHandle 必须支持写入。

在同一个文件上多次使用 fsPromises.writeFile() 且不等待 Promise 被解决(或被拒绝)是不安全的。

FS 常量#

中英对照提交修改

以下常量由 fs.constants 输出。

并非所有操作系统都可以使用每个常量。

文件可访问性的常量#

中英对照提交修改

以下常量适用于 fs.access()

常量 说明
F_OK 表明文件对调用进程可见。 这对于判断文件是否存在很有用,但对 rwx 权限没有任何说明。 如果未指定模式,则默认值为该值。
R_OK 表明调用进程可以读取文件。
W_OK 表明调用进程可以写入文件。
X_OK 表明调用进程可以执行文件。 在 Windows 上无效(表现得像 fs.constants.F_OK)。

文件拷贝的常量#

中英对照提交修改

以下常量适用于 fs.copyFile()

常量 说明
COPYFILE_EXCL 如果目标路径已存在,则拷贝操作将失败。
COPYFILE_FICLONE 拷贝操作将尝试创建写时拷贝链接。 如果底层平台不支持写时拷贝,则使用备选的拷贝机制。
COPYFILE_FICLONE_FORCE 拷贝操作将尝试创建写时拷贝链接。 如果底层平台不支持写时拷贝,则拷贝操作将失败。

文件打开的常量#

中英对照提交修改

以下常量适用于 fs.open()

常量 说明
O_RDONLY 表明打开文件用于只读访问。
O_WRONLY 表明打开文件用于只写访问。
O_RDWR 表明打开文件用于读写访问。
O_CREAT 表明如果文件尚不存在则创建该文件。
O_EXCL 表明如果设置了 O_CREAT 标志且文件已存在,则打开文件应该失败。
O_NOCTTY 表明如果路径是终端设备,则打开该路径不应该造成该终端变成进程的控制终端(如果进程还没有终端)。
O_TRUNC 表明如果文件存在且是常规文件、并且文件成功打开以进行写入访问,则其长度应截断为零。
O_APPEND 表明数据将追加到文件末尾。
O_DIRECTORY 表明如果路径不是目录,则打开应该失败。
O_NOATIME 表明文件系统的读取访问将不再导致与文件相关联的 atime 信息的更新。 仅在 Linux 操作系统上可用。
O_NOFOLLOW 表明如果路径是符号链接,则打开应该失败。
O_SYNC 表明文件是为同步 I/O 打开的,写入操作将等待文件的完整性。
O_DSYNC 表明文件是为同步 I/O 打开的,写入操作将等待数据的完整性
O_SYMLINK 表明打开符号链接自身,而不是它指向的资源。
O_DIRECT 表明将尝试最小化文件 I/O 的缓存效果。
O_NONBLOCK 表明在可能的情况下以非阻塞模式打开文件。

文件类型的常量#

中英对照提交修改

以下常量适用于 fs.Stats 对象的 mode 属性,用于决定文件的类型。

常量 说明
S_IFMT 用于提取文件类型代码的位掩码。
S_IFREG 表示常规文件。
S_IFDIR 表示目录。
S_IFCHR 表示面向字符的设备文件。
S_IFBLK 表示面向块的设备文件。
S_IFIFO 表示 FIFO 或管道。
S_IFLNK 表示符号链接。
S_IFSOCK 表示套接字。

文件模式的常量#

中英对照提交修改

以下常量适用于 fs.Stats 对象的 mode 属性,用于决定文件的访问权限。

常量 说明
S_IRWXU 表明所有者可读、可写、可执行。
S_IRUSR 表明所有者可读。
S_IWUSR 表明所有者可写。
S_IXUSR 表明所有者可执行。
S_IRWXG 表明群组可读、可写、可执行。
S_IRGRP 表明群组可读。
S_IWGRP 表明群组可写。
S_IXGRP 表明群组可执行。
S_IRWXO 表明其他人可读、可写、可执行。
S_IROTH 表明其他人可读。
S_IWOTH 表明其他人可写。
S_IXOTH 表明其他人可执行。

文件系统标志#

中英对照提交修改

flag 选项采用字符串时,可用以下标志:

  • 'a' - 打开文件用于追加。如果文件不存在,则创建该文件。

  • 'ax' - 与 'a' 相似,但如果路径已存在则失败。

  • 'a+' - 打开文件用于读取和追加。如果文件不存在,则创建该文件。

  • 'ax+' - 与 'a+' 相似,但如果路径已存在则失败。

  • 'as' - 以同步模式打开文件用于追加。如果文件不存在,则创建该文件。

  • 'as+' - 以同步模式打开文件用于读取和追加。如果文件不存在,则创建该文件。

  • 'r' - 打开文件用于读取。如果文件不存在,则出现异常。

  • 'r+' - 打开文件用于读取和写入。如果文件不存在,则出现异常。

  • 'rs+' - 以同步模式打开文件用于读取和写入。指示操作系统绕过本地的文件系统缓存。

    这对于在 NFS 挂载上打开文件时非常有用,因为它允许跳过可能过时的本地缓存。 它对 I/O 性能有非常实际的影响,因此除非需要,否则不建议使用此标志。

    这不会将 fs.open()fsPromises.open() 转换为同步的阻塞调用。 如果需要同步的操作,则应使用 fs.openSync() 之类的。

  • 'w' - 打开文件用于写入。如果文件不存在则创建文件,如果文件已存在则截断文件。

  • 'wx' - 与 'w' 相似,但如果路径已存在则失败。

  • 'w+' - 打开文件用于读取和写入。如果文件不存在则创建文件,如果文件已存在则截断文件。

  • 'wx+' - 与 'w+' 相似,但如果路径已存在则失败。

flag 也可以是一个数字,参阅 open(2) 文档。 常用的常量可以从 fs.constants 获取。 在 Windows 上,标志会被适当地转换为等效的标志,例如 O_WRONLY 转换为 FILE_GENERIC_WRITEO_EXCL|O_CREAT 转换为能被 CreateFileW 接受的 CREATE_NEW

特有的 'x' 标志( open(2) 中的 O_EXCL 标志)可以确保路径是新创建的。 在 POSIX 系统上,即使路径是一个符号链接且指向一个不存在的文件,它也会被视为已存在。 该特有标志不一定适用于网络文件系统。

在 Linux 上,当以追加模式打开文件时,写入无法指定位置。 内核会忽略位置参数,并始终将数据追加到文件的末尾。

如果要修改文件而不是覆盖文件,则标志模式应为 'r+' 模式而不是默认的 'w' 模式。

某些标志的行为是特定于平台的。 例如,在 macOS 和 Linux 上使用 'a+' 标志打开目录(参阅下面的示例)会返回一个错误。 而在 Windows 和 FreeBSD 上,则返回一个文件描述符或 FileHandle

// 在 macOS 和 Linux 上:
fs.open('<目录>', 'a+', (err, fd) => {
  // => [Error: EISDIR: illegal operation on a directory, open <目录>]
});

// 在 Windows 和 FreeBSD 上:
fs.open('<目录>', 'a+', (err, fd) => {
  // => null, <fd>
});

在 Windows 上,使用 'w' 标志打开现存的隐藏文件(通过 fs.open()fs.writeFile()fsPromises.open())会抛出 EPERM。 现存的隐藏文件可以使用 'r+' 标志打开用于写入。

调用 fs.ftruncate()fsPromises.ftruncate() 可以用于重置文件的内容。