文件系统#

稳定性:2 - 稳定

node:fs 模块提供了以符合标准 POSIX 函数的方式与文件系统进行交互的能力。

使用基于 Promise 的 API

import * as fs from 'node:fs/promises';
const fs = require('node:fs/promises');

使用回调和同步 API

import * as fs from 'node:fs';
const fs = require('node:fs');

所有文件系统操作都有同步、回调和基于 Promise 的形式,并且可以使用 CommonJS 语法和 ES6 模块 (ESM) 进行访问。

Promise 示例#

基于 Promise 的操作会返回一个 Promise,该 Promise 在异步操作完成时兑现(fulfilled)。

import { unlink } from 'node:fs/promises';

try {
  await unlink('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (error) {
  console.error('there was an error:', error.message);
}
const { unlink } = require('node:fs/promises');

(async function(path) {
  try {
    await unlink(path);
    console.log(`successfully deleted ${path}`);
  } catch (error) {
    console.error('there was an error:', error.message);
  }
})('/tmp/hello');

回调示例#

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

import { unlink } from 'node:fs';

unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});
const { unlink } = require('node:fs');

unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});

当需要最大性能(在执行时间和内存分配方面)时,基于回调的 node:fs 模块 API 版本优于基于 Promise 的 API。

同步示例#

同步 API 会阻塞 Node.js 事件循环和后续的 JavaScript 执行,直到操作完成。异常会立即抛出,可以使用 try…catch 处理,或允许其向上传播。

import { unlinkSync } from 'node:fs';

try {
  unlinkSync('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (err) {
  // handle the error
}
const { unlinkSync } = require('node:fs');

try {
  unlinkSync('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (err) {
  // handle the error
}

Promises API#

fs/promises API 提供了返回 Promise 的异步文件系统方法。

Promise API 使用底层 Node.js 线程池在事件循环线程之外执行文件系统操作。这些操作不是同步的或线程安全的。在对同一个文件进行多次并发修改时必须小心,否则可能会发生数据损坏。

类:FileHandle#

<FileHandle> 对象是数字文件描述符的对象包装器。

<FileHandle> 对象的实例由 fsPromises.open() 方法创建。

所有 <FileHandle> 对象都是 <EventEmitter>

如果 <FileHandle> 未使用 filehandle.close() 方法关闭,它将尝试自动关闭文件描述符并发出进程警告,有助于防止内存泄漏。请不要依赖此行为,因为它可能不可靠,且文件可能不会被关闭。相反,请务必显式关闭 <FileHandle>。Node.js 未来可能会更改此行为。

事件:'close'#

<FileHandle> 已关闭且无法再使用时,会发出 'close' 事件。

filehandle.appendFile(data[, options])#

filehandle.writeFile() 的别名。

当操作文件句柄时,模式不能更改为使用 fsPromises.open() 设置的模式。因此,这等同于 filehandle.writeFile()

filehandle.chmod(mode)#
  • mode <integer> 文件模式位掩码。
  • 返回:<Promise> 成功时以 undefined 兑现。

修改文件权限。参见 chmod(2)

filehandle.chown(uid, gid)#
  • uid <integer> 文件的新所有者用户 ID。
  • gid <integer> 文件的新所属组 ID。
  • 返回:<Promise> 成功时以 undefined 兑现。

更改文件所有权。chown(2) 的封装。

filehandle.close()#
  • 返回:<Promise> 成功时以 undefined 兑现。

在等待句柄上的任何挂起操作完成后关闭文件句柄。

import { open } from 'node:fs/promises';

let filehandle;
try {
  filehandle = await open('thefile.txt', 'r');
} finally {
  await filehandle?.close();
}
filehandle.createReadStream([options])#
  • 返回:<fs.ReadStream>
  • options 可以包含 startend 值,以读取文件的一定字节范围,而不是整个文件。startend 都是闭区间(包含自身)且从 0 开始计数,允许的值在 [0, Number.MAX_SAFE_INTEGER] 范围内。如果省略 start 或其为 undefined,则 filehandle.createReadStream() 会从当前文件位置顺序读取。encoding 可以是 <Buffer> 所接受的任何编码。

    如果 FileHandle 指向仅支持阻塞读取的字符设备(如键盘或声卡),则读取操作会一直持续到数据可用为止。这可能会阻止进程退出,并阻止流自然关闭。

    默认情况下,流在销毁后会发出 'close' 事件。将 emitClose 选项设置为 false 以更改此行为。

    import { open } from 'node:fs/promises';
    
    const fd = await open('/dev/input/event0');
    // Create a stream from some character device.
    const stream = fd.createReadStream();
    setTimeout(() => {
      stream.close(); // This may not close the stream.
      // Artificially marking end-of-stream, as if the underlying resource had
      // indicated end-of-file by itself, allows the stream to close.
      // This does not cancel pending read operations, and if there is such an
      // operation, the process may still not be able to exit successfully
      // until it finishes.
      stream.push(null);
      stream.read(0);
    }, 100);
    

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

    读取 100 字节长文件的最后 10 字节的示例

    import { open } from 'node:fs/promises';
    
    const fd = await open('sample.txt');
    fd.createReadStream({ start: 90, end: 99 });
    
    filehandle.createWriteStream([options])#
  • 返回:<fs.WriteStream>
  • options 也可以包含 start 选项,以允许在文件开头之后的某个位置写入数据,允许的值在 [0, Number.MAX_SAFE_INTEGER] 范围内。修改文件而不是替换文件可能需要将 flagsopen 选项设置为 r+ 而不是默认的 rencoding 可以是 <Buffer> 所接受的任何编码。

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

    默认情况下,流在销毁后会发出 'close' 事件。将 emitClose 选项设置为 false 以更改此行为。

    filehandle.datasync()#
    • 返回:<Promise> 成功时以 undefined 兑现。

    强制将与文件关联的所有当前排队的 I/O 操作刷新到操作系统的同步 I/O 完成状态。详细信息请参考 POSIX fdatasync(2) 文档。

    filehandle.sync 不同,此方法不会刷新修改后的元数据。

    filehandle.fd#
    filehandle.pull([...transforms][, options])#

    稳定性:1 - 实验性

    • ...transforms <Function> | <Object> 可选的转换操作,通过 stream/iter pull() 应用。
    • options <Object>
    • signal <AbortSignal>
    • autoClose <boolean> 在流结束时关闭文件句柄。默认值: false
    • start <number> 开始读取的字节偏移量。指定时,读取使用显式定位(pread 语义)。默认值: 当前文件位置。
    • limit <number> 迭代器结束前读取的最大字节数。读取在传递了 limit 字节或到达 EOF 时停止,以先发生者为准。默认值: 读取直到 EOF。
    • chunkSize <number> 为每次读取操作分配的缓冲区大小(以字节为单位)。默认值: 131072 (128 KB)。
  • 返回:{AsyncIterable<Uint8Array[]>}
  • 使用 node:stream/iter 拉取模型以异步可迭代对象的形式返回文件内容。读取以 chunkSize 字节(默认 128 KB)的块执行。如果提供了转换器,它们将通过 stream/iter pull() 应用。

    在消耗可迭代对象时,文件句柄被锁定;当迭代完成、发生错误或消费者中断时,文件句柄被解锁。

    此函数仅在启用 --experimental-stream-iter 标志时可用。

    import { open } from 'node:fs/promises';
    import { text } from 'node:stream/iter';
    import { compressGzip } from 'node:zlib/iter';
    
    const fh = await open('input.txt', 'r');
    
    // Read as text
    console.log(await text(fh.pull({ autoClose: true })));
    
    // Read 1 KB starting at byte 100
    const fh2 = await open('input.txt', 'r');
    console.log(await text(fh2.pull({ start: 100, limit: 1024, autoClose: true })));
    
    // Read with compression
    const fh3 = await open('input.txt', 'r');
    const compressed = fh3.pull(compressGzip(), { autoClose: true });
    const { open } = require('node:fs/promises');
    const { text } = require('node:stream/iter');
    const { compressGzip } = require('node:zlib/iter');
    
    async function run() {
      const fh = await open('input.txt', 'r');
    
      // Read as text
      console.log(await text(fh.pull({ autoClose: true })));
    
      // Read 1 KB starting at byte 100
      const fh2 = await open('input.txt', 'r');
      console.log(await text(fh2.pull({ start: 100, limit: 1024, autoClose: true })));
    
      // Read with compression
      const fh3 = await open('input.txt', 'r');
      const compressed = fh3.pull(compressGzip(), { autoClose: true });
    }
    
    run().catch(console.error);
    
    filehandle.pullSync([...transforms][, options])#

    稳定性:1 - 实验性

    • ...transforms <Function> | <Object> 可选的转换操作,通过 stream/iter pullSync() 应用。
    • options <Object>
    • autoClose <boolean> 在流结束时关闭文件句柄。默认值: false
    • start <number> 开始读取的字节偏移量。指定时,读取使用显式定位。默认值: 当前文件位置。
    • limit <number> 迭代器结束前读取的最大字节数。默认值: 读取直到 EOF。
    • chunkSize <number> 为每次读取操作分配的缓冲区大小(以字节为单位)。默认值: 131072 (128 KB)。
  • 返回:{Iterable<Uint8Array[]>}
  • filehandle.pull() 的同步对应物。返回一个同步可迭代对象,该对象在主线程上使用同步 I/O 读取文件。读取以 chunkSize 字节(默认 128 KB)的块执行。

    在消耗可迭代对象时,文件句柄被锁定。与异步 pull() 不同,由于所有操作都是同步的,此方法不支持 AbortSignal

    此函数仅在启用 --experimental-stream-iter 标志时可用。

    import { open } from 'node:fs/promises';
    import { textSync, pipeToSync } from 'node:stream/iter';
    import { compressGzipSync, decompressGzipSync } from 'node:zlib/iter';
    
    const fh = await open('input.txt', 'r');
    
    // Read as text (sync)
    console.log(textSync(fh.pullSync({ autoClose: true })));
    
    // Sync compress pipeline: file -> gzip -> file
    const src = await open('input.txt', 'r');
    const dst = await open('output.gz', 'w');
    pipeToSync(src.pullSync(compressGzipSync(), { autoClose: true }), dst.writer({ autoClose: true }));
    const { open } = require('node:fs/promises');
    const { textSync, pipeToSync } = require('node:stream/iter');
    const { compressGzipSync, decompressGzipSync } = require('node:zlib/iter');
    
    async function run() {
      const fh = await open('input.txt', 'r');
    
      // Read as text (sync)
      console.log(textSync(fh.pullSync({ autoClose: true })));
    
      // Sync compress pipeline: file -> gzip -> file
      const src = await open('input.txt', 'r');
      const dst = await open('output.gz', 'w');
      pipeToSync(
        src.pullSync(compressGzipSync(), { autoClose: true }),
        dst.writer({ autoClose: true }),
      );
    }
    
    run().catch(console.error);
    
    filehandle.read(buffer, offset, length, position)#
    • buffer <Buffer> | <TypedArray> | <DataView> 一个将被读取的文件数据填充的缓冲区。
    • offset <integer> 缓冲区中开始填充的位置。默认值: 0
    • length <integer> 要读取的字节数。默认值: buffer.byteLength - offset
    • position <integer> | <bigint> | <null> 从文件开始读取数据的位置。如果为 null-1,则从当前文件位置读取数据,并更新该位置。如果 position 是非负整数,则当前文件位置保持不变。默认值: null
    • 返回:<Promise> 成功时以一个包含两个属性的对象兑现

    从文件中读取数据并将其存储在给定的缓冲区中。

    如果文件未被并发修改,当读取的字节数为零时,即到达文件末尾。

    filehandle.read([options])#
    • options <Object>
    • buffer <Buffer> | <TypedArray> | <DataView> 一个将被读取的文件数据填充的缓冲区。默认值: Buffer.alloc(16384)
    • offset <integer> 缓冲区中开始填充的位置。默认值: 0
    • length <integer> 要读取的字节数。默认值: buffer.byteLength - offset
    • position <integer> | <bigint> | <null> 从文件开始读取数据的位置。如果为 null-1,则从当前文件位置读取数据,并更新该位置。如果 position 是非负整数,则当前文件位置保持不变。默认值: null
  • 返回:<Promise> 成功时以一个包含两个属性的对象兑现
  • 从文件中读取数据并将其存储在给定的缓冲区中。

    如果文件未被并发修改,当读取的字节数为零时,即到达文件末尾。

    filehandle.read(buffer[, options])#
    • buffer <Buffer> | <TypedArray> | <DataView> 一个将被读取的文件数据填充的缓冲区。
    • options <Object>
    • offset <integer> 缓冲区中开始填充的位置。默认值: 0
    • length <integer> 要读取的字节数。默认值: buffer.byteLength - offset
    • position <integer> | <bigint> | <null> 从文件开始读取数据的位置。如果为 null-1,则从当前文件位置读取数据,并更新该位置。如果 position 是非负整数,则当前文件位置保持不变。默认值: null
  • 返回:<Promise> 成功时以一个包含两个属性的对象兑现
  • 从文件中读取数据并将其存储在给定的缓冲区中。

    如果文件未被并发修改,当读取的字节数为零时,即到达文件末尾。

    filehandle.readableWebStream([options])#
  • 返回:<ReadableStream>

    返回一个面向字节的 ReadableStream,可用于读取文件内容。

    如果多次调用此方法,或者在 FileHandle 关闭或正在关闭后调用,则会抛出错误。

    import {
      open,
    } from 'node:fs/promises';
    
    const file = await open('./some/file/to/read');
    
    for await (const chunk of file.readableWebStream())
      console.log(chunk);
    
    await file.close();
    const {
      open,
    } = require('node:fs/promises');
    
    (async () => {
      const file = await open('./some/file/to/read');
    
      for await (const chunk of file.readableWebStream())
        console.log(chunk);
    
      await file.close();
    })();
    

    虽然 ReadableStream 会将文件读取到完成,但它不会自动关闭 FileHandle。用户代码仍必须调用 fileHandle.close() 方法,除非 autoClose 选项设置为 true

  • filehandle.readFile(options)#
    • options <Object> | <string>
    • 返回:<Promise> 成功读取时以文件内容兑现。如果未指定编码(使用 options.encoding),则数据作为 <Buffer> 对象返回。否则,数据将是字符串。

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

    如果 options 是字符串,则它指定 encoding

    <FileHandle> 必须支持读取。

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

    filehandle.readLines([options])#
  • 返回:<readline.InterfaceConstructor>
  • 用于创建 readline 接口并流式传输文件的便捷方法。有关选项,请参见 filehandle.createReadStream()

    import { open } from 'node:fs/promises';
    
    const file = await open('./some/file/to/read');
    
    for await (const line of file.readLines()) {
      console.log(line);
    }
    const { open } = require('node:fs/promises');
    
    (async () => {
      const file = await open('./some/file/to/read');
    
      for await (const line of file.readLines()) {
        console.log(line);
      }
    })();
    
    filehandle.readv(buffers[, position])#

    从文件读取并写入到 <ArrayBufferView> 数组中

    filehandle.stat([options])#
  • 返回:<Promise> 以文件的 <fs.Stats> 兑现。
  • filehandle.sync()#
    • 返回:<Promise> 成功时以 undefined 兑现。

    请求将打开文件描述符的所有数据刷新到存储设备。具体实现特定于操作系统和设备。详细信息请参考 POSIX fsync(2) 文档。

    filehandle.truncate(len)#

    截断文件。

    如果文件大于 len 字节,则文件中仅保留前 len 字节。

    以下示例仅保留文件的前四个字节

    import { open } from 'node:fs/promises';
    
    let filehandle = null;
    try {
      filehandle = await open('temp.txt', 'r+');
      await filehandle.truncate(4);
    } finally {
      await filehandle?.close();
    }
    

    如果文件以前短于 len 字节,则它会被扩展,扩展的部分会填充空字节 ('\0')

    如果 len 为负数,则使用 0

    filehandle.utimes(atime, mtime)#

    更改由 <FileHandle> 引用的对象的文件系统时间戳,并在成功后以无参数的 promise 兑现。

    filehandle.write(buffer, offset[, length[, position]])#
    • buffer <Buffer> | <TypedArray> | <DataView>
    • offset <integer> buffer 内要写入数据开始的位置。
    • length <integer> 要从 buffer 写入的字节数。默认值: buffer.byteLength - offset
    • position <integer> | <null> 距文件开头的偏移量,应在此处写入来自 buffer 的数据。如果 position 不是 number,则数据将在当前位置写入。详细信息请参考 POSIX pwrite(2) 文档。默认值: null
    • 返回:<Promise>

    buffer 写入文件。

    promise 兑现时会返回一个包含两个属性的对象

    在未等待 promise 兑现(或拒绝)之前,在同一个文件上多次使用 filehandle.write() 是不安全的。对于这种情况,请使用 filehandle.createWriteStream()

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

    filehandle.write(buffer[, options])#
  • 返回:<Promise>
  • buffer 写入文件。

    与上面的 filehandle.write 函数类似,此版本接受一个可选的 options 对象。如果未指定 options 对象,它将使用上述默认值。

    filehandle.write(string[, position[, encoding]])#
    • string <string>
    • position <integer> | <null> 距文件开头的偏移量,应在此处写入来自 string 的数据。如果 position 不是 number,则数据将在当前位置写入。详细信息请参考 POSIX pwrite(2) 文档。默认值: null
    • encoding <string> 预期的字符串编码。默认值: 'utf8'
    • 返回:<Promise>

    string 写入文件。如果 string 不是字符串,promise 将会被拒绝并抛出错误。

    promise 兑现时会返回一个包含两个属性的对象

    • bytesWritten <integer> 写入的字节数
    • buffer <string> 对写入的 string 的引用。

    在未等待 promise 兑现(或拒绝)之前,在同一个文件上多次使用 filehandle.write() 是不安全的。对于这种情况,请使用 filehandle.createWriteStream()

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

    filehandle.writeFile(data, options)#

    异步将数据写入文件,如果文件已存在则替换它。data 可以是字符串、缓冲区、<AsyncIterable><Iterable> 对象。成功时以无参数的 promise 兑现。

    如果 options 是字符串,则它指定 encoding

    <FileHandle> 必须支持写入。

    在未等待 promise 兑现(或拒绝)之前,在同一个文件上多次使用 filehandle.writeFile() 是不安全的。

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

    filehandle.writev(buffers[, position])#

    <ArrayBufferView> 数组写入文件。

    promise 兑现时会返回一个包含两个属性的对象

    在未等待 promise 兑现(或拒绝)之前,在同一个文件上多次调用 writev() 是不安全的。

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

    filehandle.writer([options])#

    稳定性:1 - 实验性

    • options <Object>
    • autoClose <boolean> 在写入器结束或失败时关闭文件句柄。默认值: false
    • start <number> 开始写入的字节偏移量。指定时,写入使用显式定位。默认值: 当前文件位置。
    • limit <number> 写入器将接受的最大字节数。超过限制的异步写入 (write(), writev()) 将被拒绝并返回 ERR_OUT_OF_RANGE。同步写入 (writeSync(), writevSync()) 将返回 false默认值: 无限制。
    • chunkSize <number> 同步写入操作的最大块大小(以字节为单位)。大于此阈值的写入将回退到异步 I/O。将其设置为匹配读取器的 chunkSize 以获得最佳 pipeTo() 性能。默认值: 131072 (128 KB)。
  • 返回:<Object>
  • write(chunk[, options]) <Function> 返回 {Promise}。接受 Uint8ArrayBuffer 或字符串(UTF-8 编码)。
  • writev(chunks[, options]) <Function> 返回 {Promise}。通过单个 writev() 系统调用使用分散/收集 I/O。接受混合的 Uint8Array/字符串数组。
    • chunks {Array<Buffer|TypedArray|DataView|string>}
    • options <Object>
    • signal <AbortSignal> 如果信号已被中止,写入将拒绝并返回 AbortError,而不执行 I/O。
  • writeSync(chunk) <Function> 返回 <boolean>。尝试同步写入。如果写入成功返回 true,如果调用者应回退到异步 write() 则返回 false。当写入器已关闭/报错、有异步操作正在运行、块超过 chunkSize 或写入将超过 limit 时返回 false
  • writevSync(chunks) <Function> 返回 <boolean>。同步批量写入。具有与 writeSync() 相同的回退语义。
    • chunks {Array<Buffer|TypedArray|DataView|string>}
  • end([options]) <Function> 返回 {Promise} 已写入的总字节数。幂等:如果已关闭则返回 totalBytesWritten,如果已在关闭过程中则返回挂起的 promise。如果写入器处于错误状态则拒绝。
    • options <Object>
    • signal <AbortSignal> 如果信号已被中止,end() 将拒绝并返回 AbortError,且写入器保持打开状态。
  • endSync() <Function> 返回 <number> | <number> 成功时已写入的总字节数;如果写入器报错或有异步操作正在运行则返回 -1。如果已关闭则为幂等。
  • fail(reason) <Function> 将写入器置于终止错误状态。同步。如果写入器已关闭或报错,则此操作为空操作。如果 autoClose 为 true,则同步关闭文件句柄。
  • 返回一个由该文件句柄支持的 node:stream/iter 写入器。

    该写入器支持 Symbol.asyncDisposeSymbol.dispose

    • await using w = fh.writer() — 如果写入器仍打开(未调用 end()),asyncDispose 将调用 fail()。如果 end() 正在挂起,它将等待它完成。
    • using w = fh.writer() — 无条件调用 fail()

    writeSync()writevSync() 方法启用了 stream/iter pipeTo() 使用的同步尝试快速路径。当读取器的块大小与写入器的 chunkSize 匹配时,pipeTo() 管道中的所有写入都会同步完成,且零 promise 开销。

    此函数仅在启用 --experimental-stream-iter 标志时可用。

    import { open } from 'node:fs/promises';
    import { from, pipeTo } from 'node:stream/iter';
    import { compressGzip } from 'node:zlib/iter';
    
    // Async pipeline
    const fh = await open('output.gz', 'w');
    await pipeTo(from('Hello!'), compressGzip(), fh.writer({ autoClose: true }));
    
    // Sync pipeline with limit
    const src = await open('input.txt', 'r');
    const dst = await open('output.txt', 'w');
    const w = dst.writer({ limit: 1024 * 1024 }); // Max 1 MB
    await pipeTo(src.pull({ autoClose: true }), w);
    await w.end();
    await dst.close();
    const { open } = require('node:fs/promises');
    const { from, pipeTo } = require('node:stream/iter');
    const { compressGzip } = require('node:zlib/iter');
    
    async function run() {
      // Async pipeline
      const fh = await open('output.gz', 'w');
      await pipeTo(from('Hello!'), compressGzip(), fh.writer({ autoClose: true }));
    
      // Sync pipeline with limit
      const src = await open('input.txt', 'r');
      const dst = await open('output.txt', 'w');
      const w = dst.writer({ limit: 1024 * 1024 }); // Max 1 MB
      await pipeTo(src.pull({ autoClose: true }), w);
      await w.end();
      await dst.close();
    }
    
    run().catch(console.error);
    
    filehandle[Symbol.asyncDispose]()#

    调用 filehandle.close() 并返回一个在文件句柄关闭时兑现的 promise。

    fsPromises.access(path[, mode])#

    测试用户对 path 指定的文件或目录的权限。mode 参数是一个可选整数,用于指定要执行的可访问性检查。mode 应为值 fs.constants.F_OK,或由 fs.constants.R_OKfs.constants.W_OKfs.constants.X_OK 中任何值的按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。查看 文件访问常量 获取 mode 的可能值。

    如果可访问性检查成功,则 promise 以无值兑现。如果任何可访问性检查失败,则 promise 以 <Error> 对象拒绝。以下示例检查当前进程是否可以读取和写入文件 /etc/passwd

    import { access, constants } from 'node:fs/promises';
    
    try {
      await access('/etc/passwd', constants.R_OK | constants.W_OK);
      console.log('can access');
    } catch {
      console.error('cannot access');
    }
    

    不建议在调用 fsPromises.open() 之前使用 fsPromises.access() 检查文件的可访问性。这样做会引入竞态条件,因为其他进程可能会在两次调用之间更改文件的状态。相反,用户代码应直接打开/读取/写入文件,并处理文件不可访问时引发的错误。

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

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

    如果 options 是字符串,则它指定 encoding

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

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

    fsPromises.chmod(path, mode)#

    更改文件的权限。

    fsPromises.chown(path, uid, gid)#

    更改文件的所有权。

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

    • src <string> | <Buffer> | <URL> 要复制的源文件名
    • dest <string> | <Buffer> | <URL> 复制操作的目标文件名
    • mode <integer> 指定复制操作行为的可选修饰符。可以创建由两个或多个值的按位或组成的掩码(例如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。默认值: 0
      • fs.constants.COPYFILE_EXCL:如果 dest 已存在,则复制操作将失败。
      • fs.constants.COPYFILE_FICLONE:复制操作将尝试创建写时复制 (copy-on-write) 再链接 (reflink)。如果平台不支持写时复制,则使用回退复制机制。
      • fs.constants.COPYFILE_FICLONE_FORCE:复制操作将尝试创建写时复制再链接。如果平台不支持写时复制,则操作将失败。
    • 返回:<Promise> 成功时以 undefined 兑现。

    异步将 src 复制到 dest。默认情况下,如果 dest 已存在,它会被覆盖。

    不对复制操作的原子性做出保证。如果目标文件已打开进行写入后发生错误,将尝试删除目标文件。

    import { copyFile, constants } from 'node:fs/promises';
    
    try {
      await copyFile('source.txt', 'destination.txt');
      console.log('source.txt was copied to destination.txt');
    } catch {
      console.error('The file could not be copied');
    }
    
    // By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
    try {
      await copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL);
      console.log('source.txt was copied to destination.txt');
    } catch {
      console.error('The file could not be copied');
    }
    

    fsPromises.cp(src, dest[, options])#

    • src <string> | <URL> 要复制的源路径。
    • dest <string> | <URL> 要复制到的目标路径。
    • options <Object>
    • dereference <boolean> 取消引用符号链接。默认值: false
    • errorOnExist <boolean>forcefalse 且目标存在时,抛出错误。默认值: false
    • filter <Function> 用于过滤复制的文件/目录的函数。返回 true 以复制项目,返回 false 以忽略它。忽略目录时,其所有内容也将被跳过。也可以返回解析为 truefalsePromise默认值: undefined
      • src <string> 要复制的源路径。
      • dest <string> 要复制到的目标路径。
      • 返回:<boolean> | <Promise> 可强制转换为 boolean 的值或以此类值兑现的 Promise
    • force <boolean> 覆盖现有文件或目录。如果您将其设置为 false 且目标存在,复制操作将忽略错误。使用 errorOnExist 选项更改此行为。默认值: true
    • mode <integer> 复制操作的修饰符。默认值: 0。参见 fsPromises.copyFile()mode 标志。
    • preserveTimestamps <boolean> 当为 true 时,将保留来自 src 的时间戳。默认值: false
    • recursive <boolean> 递归复制目录。默认值: false
    • verbatimSymlinks <boolean> 当为 true 时,将跳过符号链接的路径解析。默认值: false
  • 返回:<Promise> 成功时以 undefined 兑现。
  • 异步将整个目录结构从 src 复制到 dest,包括子目录和文件。

    将目录复制到另一个目录时,不支持 glob 模式,且行为类似于 cp dir1/ dir2/

    fsPromises.glob(pattern[, options])#

    • pattern <string> | <string[]>
    • options <Object>
    • cwd <string> | <URL> 当前工作目录。默认值: process.cwd()
    • exclude <Function> | <string[]> 用于过滤掉文件/目录的函数或要排除的 glob 模式列表。如果提供了函数,则返回 true 以排除该项目,返回 false 以包含它。默认值: undefined。如果提供了字符串数组,则每个字符串都应是指定要排除路径的 glob 模式。注意:不支持否定模式(例如 '!foo.js')。
    • withFileTypes <boolean> 如果 glob 应将路径作为 Dirent 返回,则为 true,否则为 false默认值: false
  • 返回:<AsyncIterator> 一个异步迭代器,它产生匹配该模式的文件的路径。
  • import { glob } from 'node:fs/promises';
    
    for await (const entry of glob('**/*.js'))
      console.log(entry);
    const { glob } = require('node:fs/promises');
    
    (async () => {
      for await (const entry of glob('**/*.js'))
        console.log(entry);
    })();
    

    fsPromises.lchmod(path, mode)#

    稳定性:0 - 已弃用

    更改符号链接的权限。

    此方法仅在 macOS 上实现。

    fsPromises.lchown(path, uid, gid)#

    更改符号链接的所有权。

    fsPromises.lutimes(path, atime, mtime)#

    以与 fsPromises.utimes() 相同的方式更改文件的访问和修改时间,不同之处在于,如果路径指向符号链接,则不会取消引用链接:而是更改符号链接本身的时间戳。

    fsPromises.link(existingPath, newPath)#

    创建从 existingPathnewPath 的新链接。详细信息请参考 POSIX link(2) 文档。

    fsPromises.lstat(path[, options])#

  • 返回:<Promise> 以给定符号链接 path<fs.Stats> 对象兑现。
  • 等同于 fsPromises.stat(),除非 path 指向的是符号链接,这种情况下将对链接本身进行 stat 操作,而不是它所指向的文件。详细信息请参考 POSIX lstat(2) 文档。

    fsPromises.mkdir(path[, options])#

    异步创建目录。

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

    import { mkdir } from 'node:fs/promises';
    
    try {
      const projectFolder = new URL('./test/project/', import.meta.url);
      const createDir = await mkdir(projectFolder, { recursive: true });
    
      console.log(`created ${createDir}`);
    } catch (err) {
      console.error(err.message);
    }
    const { mkdir } = require('node:fs/promises');
    const { join } = require('node:path');
    
    async function makeDirectory() {
      const projectFolder = join(__dirname, 'test', 'project');
      const dirCreation = await mkdir(projectFolder, { recursive: true });
    
      console.log(dirCreation);
      return dirCreation;
    }
    
    makeDirectory().catch(console.error);
    

    fsPromises.mkdtemp(prefix[, options])#

    创建一个唯一的临时目录。通过在提供的 prefix 末尾附加六个随机字符来生成唯一的目录名。由于平台不一致,请避免在 prefix 中使用末尾的 X 字符。某些平台(尤其是 BSD)可能会返回超过六个随机字符,并将 prefix 中末尾的 X 字符替换为随机字符。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定使用的字符编码。

    import { mkdtemp } from 'node:fs/promises';
    import { join } from 'node:path';
    import { tmpdir } from 'node:os';
    
    try {
      await mkdtemp(join(tmpdir(), 'foo-'));
    } catch (err) {
      console.error(err);
    }
    

    fsPromises.mkdtemp() 方法会将六个随机选择的字符直接附加到 prefix 字符串上。例如,给定目录 /tmp,如果目的是在 /tmp *内*创建临时目录,则 prefix 必须以特定于平台的路径分隔符结尾(require('node:path').sep)。

    fsPromises.mkdtempDisposable(prefix[, options])#

    生成的 Promise 持有一个异步可处置对象,其 path 属性保存了已创建的目录路径。当对象被处置时,如果该目录仍然存在,它及其内容将被异步移除。如果目录无法删除,处置时将抛出错误。该对象拥有一个异步 remove() 方法,可以执行相同的任务。

    此函数及结果对象上的处置函数均为异步的,因此应与 await + await using 一起使用,例如:await using dir = await fsPromises.mkdtempDisposable('prefix')

    详细信息,请参阅 fsPromises.mkdtemp() 的文档。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定使用的字符编码。

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

    打开一个 <FileHandle>

    详细信息请参考 POSIX open(2) 文档。

    根据 命名文件、路径和命名空间 文档,某些字符(< > : " / \ | ? *)在 Windows 下是保留字符。在 NTFS 下,如果文件名包含冒号,Node.js 将打开一个文件系统流,如此 MSDN 页面所述。

    fsPromises.opendir(path[, options])#

  • 返回: <Promise> 兑现为一个 <fs.Dir>
  • 异步打开一个用于迭代扫描的目录。详细信息请参考 POSIX opendir(3) 文档。

    创建一个 <fs.Dir>,其中包含用于读取和清理目录的所有后续函数。

    encoding 选项设置打开目录及后续读取操作时 path 的编码。

    使用异步迭代的示例

    import { opendir } from 'node:fs/promises';
    
    try {
      const dir = await opendir('./');
      for await (const dirent of dir)
        console.log(dirent.name);
    } catch (err) {
      console.error(err);
    }
    

    使用异步迭代器时,<fs.Dir> 对象将在迭代器退出后自动关闭。

    fsPromises.readdir(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <string> | <Object>
      • encoding <string> 默认值: 'utf8'
      • withFileTypes <boolean> 默认值: false
      • recursive <boolean> 如果为 true,则递归读取目录内容。在递归模式下,它将列出所有文件、子文件和目录。 默认值: false
    • 返回: <Promise> 兑现为一个目录中文件名的数组,不包括 '.''..'

    读取目录的内容。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定文件名使用的字符编码。如果 encoding 设置为 'buffer',则返回的文件名将作为 <Buffer> 对象传递。

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

    import { readdir } from 'node:fs/promises';
    
    try {
      const files = await readdir(path);
      for (const file of files)
        console.log(file);
    } catch (err) {
      console.error(err);
    }
    

    fsPromises.readFile(path[, options])#

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

    如果未指定编码(使用 options.encoding),则数据作为 <Buffer> 对象返回。否则,数据将是一个字符串。

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

    path 是一个目录时,fsPromises.readFile() 的行为因平台而异。在 macOS、Linux 和 Windows 上,Promise 将因错误而被拒绝。在 FreeBSD 上,将返回目录内容的表示形式。

    读取与运行代码位于同一目录下的 package.json 文件的示例

    import { readFile } from 'node:fs/promises';
    try {
      const filePath = new URL('./package.json', import.meta.url);
      const contents = await readFile(filePath, { encoding: 'utf8' });
      console.log(contents);
    } catch (err) {
      console.error(err.message);
    }
    const { readFile } = require('node:fs/promises');
    const { resolve } = require('node:path');
    async function logFile() {
      try {
        const filePath = resolve('./package.json');
        const contents = await readFile(filePath, { encoding: 'utf8' });
        console.log(contents);
      } catch (err) {
        console.error(err.message);
      }
    }
    logFile();
    

    可以使用 <AbortSignal> 中止正在进行的 readFile。如果请求被中止,返回的 Promise 将因 AbortError 而被拒绝。

    import { readFile } from 'node:fs/promises';
    
    try {
      const controller = new AbortController();
      const { signal } = controller;
      const promise = readFile(fileName, { signal });
    
      // Abort the request before the promise settles.
      controller.abort();
    
      await promise;
    } catch (err) {
      // When a request is aborted - err is an AbortError
      console.error(err);
    }
    

    中止正在进行的请求不会中止单个操作系统请求,而是中止 fs.readFile 执行的内部缓冲。

    任何指定的 <FileHandle> 都必须支持读取。

    fsPromises.readlink(path[, options])#

    读取由 path 引用的符号链接的内容。详细信息请参考 POSIX readlink(2) 文档。成功时,Promise 会以 linkString 兑现。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定返回的链接路径所使用的字符编码。如果 encoding 设置为 'buffer',则返回的链接路径将作为 <Buffer> 对象传递。

    fsPromises.realpath(path[, options])#

    使用与 fs.realpath.native() 函数相同的语义确定 path 的实际位置。

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

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定路径所使用的字符编码。如果 encoding 设置为 'buffer',则返回的路径将作为 <Buffer> 对象传递。

    在 Linux 上,当 Node.js 链接到 musl libc 时,procfs 文件系统必须挂载在 /proc 上,此函数才能工作。Glibc 没有此限制。

    fsPromises.rename(oldPath, newPath)#

    oldPath 重命名为 newPath

    fsPromises.rmdir(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object> 目前没有暴露任何选项。过去有 recursivemaxBusyTriesemfileWait 的选项,但它们已被弃用并移除。为了向后兼容,仍然接受 options 参数,但它不会被使用。
    • 返回:<Promise> 成功时以 undefined 兑现。

    移除由 path 标识的目录。

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

    要获得类似于 Unix 命令 rm -rf 的行为,请使用带有 { recursive: true, force: true } 选项的 fsPromises.rm()

    fsPromises.rm(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • force <boolean> 如果为 true,则在 path 不存在时忽略异常。 默认值: false
    • maxRetries <integer> 如果遇到 EBUSYEMFILEENFILEENOTEMPTYEPERM 错误,Node.js 将以线性退避等待的方式重试该操作,每次尝试的等待时间比上一次长 retryDelay 毫秒。此选项表示重试次数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 0
    • recursive <boolean> 如果为 true,则执行递归目录移除。在递归模式下,失败的操作会进行重试。 默认值: false
    • retryDelay <integer> 重试之间等待的毫秒数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 100
  • 返回:<Promise> 成功时以 undefined 兑现。
  • 移除文件和目录(基于标准的 POSIX rm 工具)。

    fsPromises.stat(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • bigint <boolean> 返回的 <fs.Stats> 对象中的数值是否应为 bigint默认值: false
    • throwIfNoEntry <boolean> 如果没有文件系统条目存在时,是否抛出异常,而不是返回 undefined默认值: true
  • 返回: <Promise> 兑现为给定 path<fs.Stats> 对象。
  • fsPromises.statfs(path[, options])#

  • 返回: <Promise> 兑现为给定 path<fs.StatFs> 对象。
  • fsPromises.symlink(target, path[, type])#

    创建符号链接。

    type 参数仅在 Windows 平台上使用,可以是 'dir''file''junction' 之一。如果 type 参数为 null,Node.js 将自动检测 target 类型并使用 'file''dir'。如果 target 不存在,将使用 'file'。Windows 交界点(junction points)要求目标路径必须是绝对路径。使用 'junction' 时,target 参数将自动规范化为绝对路径。NTFS 卷上的交界点只能指向目录。

    fsPromises.truncate(path[, len])#

    path 处的内容截断(缩短或延长长度)为 len 字节。

    fsPromises.unlink(path)#

    如果 path 引用符号链接,则删除该链接,而不影响该链接所指向的文件或目录。如果 path 引用非符号链接的文件路径,则删除该文件。详细信息请参考 POSIX unlink(2) 文档。

    fsPromises.utimes(path, atime, mtime)#

    更改由 path 引用的对象的文件系统时间戳。

    atimemtime 参数遵循以下规则:

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

    fsPromises.watch(filename[, options])#

    • filename <string> | <Buffer> | <URL>
    • options <string> | <Object>
      • persistent <boolean> 指示只要有文件在被监视,进程是否应继续运行。 默认值: true
      • recursive <boolean> 指示是否应监视所有子目录,还是仅监视当前目录。当指定了目录时,这在受支持的平台上有效(详见注意事项)。 默认值: false
      • encoding <string> 指定用于传递给监听器的文件名的字符编码。 默认值: 'utf8'
      • signal <AbortSignal> 一个用于指示监视器何时停止的 <AbortSignal>
      • maxQueue <number> 指定在返回的 <AsyncIterator> 迭代之间排队的事件数。 默认值: 2048
      • overflow <string> 当排队的事件多于 maxQueue 允许的数量时,设为 'ignore''throw''ignore' 表示丢弃溢出事件并发出警告,而 'throw' 表示抛出异常。 默认值: 'ignore'
      • ignore <string> | <RegExp> | <Function> | <Array> 要忽略的模式。字符串是 glob 模式(使用 minimatch),RegExp 模式会针对文件名进行测试,而函数会接收文件名并返回 true 以忽略。 默认值: undefined
    • 返回: <AsyncIterator>,包含以下属性的对象

    返回一个异步迭代器,监视 filename 上的变更,其中 filename 可以是文件或目录。

    const { watch } = require('node:fs/promises');
    
    const ac = new AbortController();
    const { signal } = ac;
    setTimeout(() => ac.abort(), 10000);
    
    (async () => {
      try {
        const watcher = watch(__filename, { signal });
        for await (const event of watcher)
          console.log(event);
      } catch (err) {
        if (err.name === 'AbortError')
          return;
        throw err;
      }
    })();
    

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

    fs.watch() 的所有 注意事项 也适用于 fsPromises.watch()

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

    将数据异步写入文件,如果文件已存在,则替换该文件。data 可以是字符串、缓冲区、<AsyncIterable><Iterable> 对象。

    如果 data 是缓冲区,则忽略 encoding 选项。

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

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

    任何指定的 <FileHandle> 都必须支持写入。

    在不等待 Promise 完成的情况下,在同一个文件上多次使用 fsPromises.writeFile() 是不安全的。

    fsPromises.readFile 类似,fsPromises.writeFile 是一个便利方法,在内部执行多次 write 调用来写入传递给它的缓冲区。对于性能敏感的代码,请考虑使用 fs.createWriteStream()filehandle.createWriteStream()

    可以使用 <AbortSignal> 取消 fsPromises.writeFile()。取消是“尽力而为”的,部分数据很可能仍然会被写入。

    import { writeFile } from 'node:fs/promises';
    import { Buffer } from 'node:buffer';
    
    try {
      const controller = new AbortController();
      const { signal } = controller;
      const data = new Uint8Array(Buffer.from('Hello Node.js'));
      const promise = writeFile('message.txt', data, { signal });
    
      // Abort the request before the promise settles.
      controller.abort();
    
      await promise;
    } catch (err) {
      // When a request is aborted - err is an AbortError
      console.error(err);
    }
    

    中止正在进行的请求不会中止单个操作系统请求,而是中止 fs.writeFile 执行的内部缓冲。

    fsPromises.constants#

    返回包含文件系统操作常用常量的一个对象。该对象与 fs.constants 相同。详见 FS 常量

    回调 API#

    回调 API 异步执行所有操作,不会阻塞事件循环,然后在完成或出错时调用回调函数。

    回调 API 使用底层的 Node.js 线程池在事件循环线程之外执行文件系统操作。这些操作不是同步的,也不具备线程安全性。当在同一个文件上执行多次并发修改时必须小心,否则可能会发生数据损坏。

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

    测试用户对 path 指定的文件或目录的权限。mode 参数是一个可选整数,用于指定要执行的可访问性检查。mode 应为值 fs.constants.F_OK,或由 fs.constants.R_OKfs.constants.W_OKfs.constants.X_OK 中任何值的按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。查看 文件访问常量 获取 mode 的可能值。

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

    import { access, constants } from 'node:fs';
    
    const file = 'package.json';
    
    // Check if the file exists in the current directory.
    access(file, constants.F_OK, (err) => {
      console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
    });
    
    // Check if the file is readable.
    access(file, constants.R_OK, (err) => {
      console.log(`${file} ${err ? 'is not readable' : 'is readable'}`);
    });
    
    // Check if the file is writable.
    access(file, constants.W_OK, (err) => {
      console.log(`${file} ${err ? 'is not writable' : 'is writable'}`);
    });
    
    // Check if the file is readable and writable.
    access(file, constants.R_OK | constants.W_OK, (err) => {
      console.log(`${file} ${err ? 'is not' : 'is'} readable and writable`);
    });
    

    不要在调用 fs.open()fs.readFile()fs.writeFile() 之前使用 fs.access() 检查文件的可访问性。这样做会引入竞态条件,因为其他进程可能在两次调用之间更改文件的状态。相反,用户代码应直接打开/读取/写入文件,并在文件无法访问时处理引发的错误。

    写入(不推荐)

    import { access, open, close } from 'node:fs';
    
    access('myfile', (err) => {
      if (!err) {
        console.error('myfile already exists');
        return;
      }
    
      open('myfile', 'wx', (err, fd) => {
        if (err) throw err;
    
        try {
          writeMyData(fd);
        } finally {
          close(fd, (err) => {
            if (err) throw err;
          });
        }
      });
    });
    

    写入(推荐)

    import { open, close } from 'node:fs';
    
    open('myfile', 'wx', (err, fd) => {
      if (err) {
        if (err.code === 'EEXIST') {
          console.error('myfile already exists');
          return;
        }
    
        throw err;
      }
    
      try {
        writeMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
    

    读取(不推荐)

    import { access, open, close } from 'node:fs';
    access('myfile', (err) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.error('myfile does not exist');
          return;
        }
    
        throw err;
      }
    
      open('myfile', 'r', (err, fd) => {
        if (err) throw err;
    
        try {
          readMyData(fd);
        } finally {
          close(fd, (err) => {
            if (err) throw err;
          });
        }
      });
    });
    

    读取(推荐)

    import { open, close } from 'node:fs';
    
    open('myfile', 'r', (err, fd) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.error('myfile does not exist');
          return;
        }
    
        throw err;
      }
    
      try {
        readMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
    

    上面的“不推荐”示例检查可访问性,然后使用文件;“推荐”示例更好,因为它们直接使用文件并处理可能出现的错误。

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

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

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

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

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

    import { appendFile } from 'node:fs';
    
    appendFile('message.txt', 'data to append', (err) => {
      if (err) throw err;
      console.log('The "data to append" was appended to file!');
    });
    

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

    import { appendFile } from 'node:fs';
    
    appendFile('message.txt', 'data to append', 'utf8', callback);
    

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

    import { open, close, appendFile } from 'node:fs';
    
    function closeFd(fd) {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
    
    open('message.txt', 'a', (err, fd) => {
      if (err) throw err;
    
      try {
        appendFile(fd, 'data to append', 'utf8', (err) => {
          closeFd(fd);
          if (err) throw err;
        });
      } catch (err) {
        closeFd(fd);
        throw err;
      }
    });
    

    fs.chmod(path, mode, callback)#

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

    详细信息请参考 POSIX chmod(2) 文档。

    import { chmod } from 'node:fs';
    
    chmod('my_file.txt', 0o775, (err) => {
      if (err) throw err;
      console.log('The permissions for file "my_file.txt" have been changed!');
    });
    
    文件模式#

    fs.chmod()fs.chmodSync() 方法中使用的 mode 参数是一个数值掩码,通过对以下常量进行逻辑 OR 运算创建

    常量 八进制 描述
    fs.constants.S_IRUSR 0o400 所有者可读
    fs.constants.S_IWUSR 0o200 所有者可写
    fs.constants.S_IXUSR 0o100 所有者可执行/搜索
    fs.constants.S_IRGRP 0o40 组可读
    fs.constants.S_IWGRP 0o20 组可写
    fs.constants.S_IXGRP 0o10 组可执行/搜索
    fs.constants.S_IROTH 0o4 其他人可读
    fs.constants.S_IWOTH 0o2 其他人可写
    fs.constants.S_IXOTH 0o1 其他人可执行/搜索

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

    数字 描述
    7 读、写和执行
    6 读和写
    5 读和执行
    4 只读
    3 写和执行
    2 只写
    1 只执行
    0 无权限

    例如,八进制值 0o765 表示

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

    当在期望文件模式的地方使用原始数字时,任何大于 0o777 的值都可能导致不支持一致工作的特定于平台的行为。因此,诸如 S_ISVTXS_ISGIDS_ISUID 等常量没有在 fs.constants 中暴露。

    注意事项:在 Windows 上只能更改写权限,并且没有实现组、所有者或其他人的权限区分。

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

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

    详细信息请参考 POSIX chown(2) 文档。

    fs.close(fd[, callback])#

    关闭文件描述符。除了可能的异常外,没有其他参数传递给完成回调。

    在任何当前通过其他 fs 操作使用的文件描述符 (fd) 上调用 fs.close() 可能导致未定义的行为。

    详细信息请参考 POSIX close(2) 文档。

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

    异步将 src 复制到 dest。默认情况下,如果 dest 已存在,它将被覆盖。除了可能的异常外,没有其他参数传递给回调函数。Node.js 不保证复制操作的原子性。如果目标文件打开写入后发生错误,Node.js 将尝试移除目标文件。

    mode 是一个可选整数,指定复制操作的行为。可以创建一个由两个或多个值按位 OR 组成的掩码(例如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。

    • fs.constants.COPYFILE_EXCL:如果 dest 已存在,则复制操作将失败。
    • fs.constants.COPYFILE_FICLONE:复制操作将尝试创建写时复制 (copy-on-write) 再链接 (reflink)。如果平台不支持写时复制,则使用回退复制机制。
    • fs.constants.COPYFILE_FICLONE_FORCE:复制操作将尝试创建写时复制再链接。如果平台不支持写时复制,则操作将失败。
    import { copyFile, constants } from 'node:fs';
    
    function callback(err) {
      if (err) throw err;
      console.log('source.txt was copied to destination.txt');
    }
    
    // destination.txt will be created or overwritten by default.
    copyFile('source.txt', 'destination.txt', callback);
    
    // By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
    copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL, callback);
    

    fs.cp(src, dest[, options], callback)#

    • src <string> | <URL> 要复制的源路径。
    • dest <string> | <URL> 要复制到的目标路径。
    • options <Object>
    • dereference <boolean> 取消引用符号链接。默认值: false
    • errorOnExist <boolean>forcefalse 且目标存在时,抛出错误。默认值: false
    • filter <Function> 用于过滤复制的文件/目录的函数。返回 true 以复制项目,返回 false 以忽略它。忽略目录时,其所有内容也将被跳过。也可以返回解析为 truefalsePromise默认值: undefined
      • src <string> 要复制的源路径。
      • dest <string> 要复制到的目标路径。
      • 返回:<boolean> | <Promise> 可强制转换为 boolean 的值或以此类值兑现的 Promise
    • force <boolean> 覆盖现有文件或目录。如果您将其设置为 false 且目标存在,复制操作将忽略错误。使用 errorOnExist 选项更改此行为。默认值: true
    • mode <integer> 复制操作的修饰符。 默认值: 0。详见 fs.copyFile()mode 标志。
    • preserveTimestamps <boolean> 当为 true 时,将保留来自 src 的时间戳。默认值: false
    • recursive <boolean> 递归复制目录。默认值: false
    • verbatimSymlinks <boolean> 当为 true 时,将跳过符号链接的路径解析。默认值: false
  • callback <Function>
  • 异步将整个目录结构从 src 复制到 dest,包括子目录和文件。

    将目录复制到另一个目录时,不支持 glob 模式,且行为类似于 cp dir1/ dir2/

    fs.createReadStream(path[, options])#

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

    如果指定了 fdReadStream 将忽略 path 参数并使用指定的文件描述符。这意味着不会发出 'open' 事件。fd 应该是阻塞的;非阻塞 fd 应该传递给 <net.Socket>

    如果 fd 指向仅支持阻塞读取的字符设备(例如键盘或声卡),读取操作直到数据可用时才会完成。这可能导致进程无法退出,流无法自然关闭。

    默认情况下,流在销毁后会发出 'close' 事件。将 emitClose 选项设置为 false 以更改此行为。

    通过提供 fs 选项,可以覆盖 openreadclose 的对应 fs 实现。提供 fs 选项时,需要重写 read。如果未提供 fd,还需要重写 open。如果 autoClosetrue,还需要重写 close

    import { createReadStream } from 'node:fs';
    
    // Create a stream from some character device.
    const stream = createReadStream('/dev/input/event0');
    setTimeout(() => {
      stream.close(); // This may not close the stream.
      // Artificially marking end-of-stream, as if the underlying resource had
      // indicated end-of-file by itself, allows the stream to close.
      // This does not cancel pending read operations, and if there is such an
      // operation, the process may still not be able to exit successfully
      // until it finishes.
      stream.push(null);
      stream.read(0);
    }, 100);
    

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

    mode 设置文件模式(权限和粘滞位),但仅在文件被创建时生效。

    读取 100 字节长文件的最后 10 字节的示例

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

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

    fs.createWriteStream(path[, options])#

    options 还可以包含一个 start 选项,以允许在文件开始之后的某个位置写入数据,允许的值在 [0, Number.MAX_SAFE_INTEGER] 范围内。修改文件而不是替换文件可能需要将 flags 选项设置为 r+ 而不是默认的 wencoding 可以是 <Buffer> 接受的任何编码。

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

    默认情况下,流在销毁后会发出 'close' 事件。将 emitClose 选项设置为 false 以更改此行为。

    通过提供 fs 选项,可以覆盖 openwritewritevclose 的对应 fs 实现。在没有 writev() 的情况下重写 write() 可能会降低性能,因为某些优化 (_writev()) 将被禁用。提供 fs 选项时,至少需要重写 writewritev 中的一个。如果未提供 fd 选项,还需要重写 open。如果 autoClosetrue,还需要重写 close

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

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

    fs.exists(path, callback)#

    稳定性: 0 - 已弃用: 请改用 fs.stat()fs.access()

    通过检查文件系统来测试给定 path 的元素是否存在。然后使用 true 或 false 调用 callback 参数。

    import { exists } from 'node:fs';
    
    exists('/etc/passwd', (e) => {
      console.log(e ? 'it exists' : 'no passwd!');
    });
    

    此回调的参数与 Node.js 的其他回调不一致。 通常,Node.js 回调的第一个参数是 err 参数,后面可选地跟其他参数。fs.exists() 回调只有一个布尔参数。这就是建议使用 fs.access() 而不是 fs.exists() 的原因之一。

    如果 path 是符号链接,则会跟踪它。因此,如果 path 存在但指向不存在的元素,则回调将接收 false

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

    写入(不推荐)

    import { exists, open, close } from 'node:fs';
    
    exists('myfile', (e) => {
      if (e) {
        console.error('myfile already exists');
      } else {
        open('myfile', 'wx', (err, fd) => {
          if (err) throw err;
    
          try {
            writeMyData(fd);
          } finally {
            close(fd, (err) => {
              if (err) throw err;
            });
          }
        });
      }
    });
    

    写入(推荐)

    import { open, close } from 'node:fs';
    open('myfile', 'wx', (err, fd) => {
      if (err) {
        if (err.code === 'EEXIST') {
          console.error('myfile already exists');
          return;
        }
    
        throw err;
      }
    
      try {
        writeMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
    

    读取(不推荐)

    import { open, close, exists } from 'node:fs';
    
    exists('myfile', (e) => {
      if (e) {
        open('myfile', 'r', (err, fd) => {
          if (err) throw err;
    
          try {
            readMyData(fd);
          } finally {
            close(fd, (err) => {
              if (err) throw err;
            });
          }
        });
      } else {
        console.error('myfile does not exist');
      }
    });
    

    读取(推荐)

    import { open, close } from 'node:fs';
    
    open('myfile', 'r', (err, fd) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.error('myfile does not exist');
          return;
        }
    
        throw err;
      }
    
      try {
        readMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
    

    上面的“不推荐”示例检查存在性,然后使用文件;“推荐”示例更好,因为它们直接使用文件并处理可能出现的错误。

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

    fs.fchmod(fd, mode, callback)#

    设置文件权限。除了可能的异常外,没有其他参数传递给完成回调。

    详细信息请参考 POSIX fchmod(2) 文档。

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

    设置文件所有者。除了可能的异常外,没有其他参数传递给完成回调。

    详细信息请参考 POSIX fchown(2) 文档。

    fs.fdatasync(fd, callback)#

    强制将与该文件相关联的所有当前排队的 I/O 操作同步到操作系统的同步 I/O 完成状态。详细信息请参考 POSIX fdatasync(2) 文档。除了可能的异常外,没有其他参数传递给完成回调。

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

  • callback <Function>
  • 使用文件描述符的 <fs.Stats> 调用回调。

    详细信息请参考 POSIX fstat(2) 文档。

    fs.fsync(fd, callback)#

    请求将打开的文件描述符的所有数据冲刷到存储设备。具体的实现取决于操作系统和设备。详细信息请参考 POSIX fsync(2) 文档。除了可能的异常外,没有其他参数传递给完成回调。

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

    截断文件描述符。除了可能的异常外,没有其他参数传递给完成回调。

    详细信息请参考 POSIX ftruncate(2) 文档。

    如果文件描述符引用的文件大于 len 字节,则文件中仅保留前 len 字节。

    例如,以下程序仅保留文件的前四个字节

    import { open, close, ftruncate } from 'node:fs';
    
    function closeFd(fd) {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
    
    open('temp.txt', 'r+', (err, fd) => {
      if (err) throw err;
    
      try {
        ftruncate(fd, 4, (err) => {
          closeFd(fd);
          if (err) throw err;
        });
      } catch (err) {
        closeFd(fd);
        if (err) throw err;
      }
    });
    

    如果文件以前短于 len 字节,则它会被扩展,扩展的部分会填充空字节 ('\0')

    如果 len 为负数,则使用 0

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

    更改由提供的文件描述符引用的对象的文件系统时间戳。详见 fs.utimes()

    fs.glob(pattern[, options], callback)#

    • pattern <string> | <string[]>

    • options <Object>

      • cwd <string> | <URL> 当前工作目录。默认值: process.cwd()
      • exclude <Function> | <string[]> 用于过滤文件/目录的函数或要排除的 glob 模式列表。如果提供了函数,返回 true 以排除项目,返回 false 以包含它。 默认值: undefined
      • withFileTypes <boolean> 如果 glob 应将路径作为 Dirent 返回,则为 true,否则为 false默认值: false
    • callback <Function>

    • 检索匹配指定模式的文件。

    import { glob } from 'node:fs';
    
    glob('**/*.js', (err, matches) => {
      if (err) throw err;
      console.log(matches);
    });
    const { glob } = require('node:fs');
    
    glob('**/*.js', (err, matches) => {
      if (err) throw err;
      console.log(matches);
    });
    

    fs.lchmod(path, mode, callback)#

    稳定性:0 - 已弃用

    更改符号链接的权限。除了可能的异常外,没有其他参数传递给完成回调。

    此方法仅在 macOS 上实现。

    详细信息请参考 POSIX lchmod(2) 文档。

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

    设置符号链接的所有者。除了可能的异常外,没有其他参数传递给完成回调。

    详细信息请参考 POSIX lchown(2) 文档。

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

    以与 fs.utimes() 相同的方式更改文件的访问和修改时间,不同之处在于,如果路径引用的是符号链接,则不会解除对链接的引用:而是更改符号链接本身的时间戳。

    除了可能的异常外,没有其他参数传递给完成回调。

    fs.link(existingPath, newPath, callback)#

    existingPath 创建到 newPath 的新链接。详细信息请参考 POSIX link(2) 文档。除了可能的异常外,没有其他参数传递给完成回调。

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

  • callback <Function>
  • 检索路径引用的符号链接的 <fs.Stats>。回调接收两个参数 (err, stats),其中 stats<fs.Stats> 对象。lstat()stat() 相同,不同之处在于如果 path 是符号链接,则会对链接本身进行 stat 操作,而不是对链接所指向的文件。

    详细信息请参考 POSIX lstat(2) 文档。

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

    异步创建目录。

    回调接收一个可能的异常,如果 recursivetrue,还会接收第一个创建的目录路径 (err[, path])。如果未创建目录(例如,如果之前已创建),当 recursivetrue 时,path 仍可能为 undefined

    可选的 options 参数可以是一个指定 mode(权限和粘滞位)的整数,或者一个包含 mode 属性和 recursive 属性的对象,用于指示是否应创建父目录。当 path 是一个已存在的目录时,仅当 recursive 为 false 时,调用 fs.mkdir() 才会导致错误。如果 recursive 为 false 且目录已存在,则会发生 EEXIST 错误。

    import { mkdir } from 'node:fs';
    
    // Create ./tmp/a/apple, regardless of whether ./tmp and ./tmp/a exist.
    mkdir('./tmp/a/apple', { recursive: true }, (err) => {
      if (err) throw err;
    });
    

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

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

    详细信息请参考 POSIX mkdir(2) 文档。

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

    创建唯一的临时目录。

    生成六个随机字符并附加在必需的 prefix 后面,以创建唯一的临时目录。由于平台不一致,请避免在 prefix 中使用末尾的 X 字符。某些平台(尤其是 BSD)可能会返回超过六个随机字符,并将 prefix 中末尾的 X 字符替换为随机字符。

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

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定使用的字符编码。

    import { mkdtemp } from 'node:fs';
    import { join } from 'node:path';
    import { tmpdir } from 'node:os';
    
    mkdtemp(join(tmpdir(), 'foo-'), (err, directory) => {
      if (err) throw err;
      console.log(directory);
      // Prints: /tmp/foo-itXde2 or C:\Users\...\AppData\Local\Temp\foo-itXde2
    });
    

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

    import { tmpdir } from 'node:os';
    import { mkdtemp } from 'node:fs';
    
    // The parent directory for the new temporary directory
    const tmpDir = tmpdir();
    
    // This method is *INCORRECT*:
    mkdtemp(tmpDir, (err, directory) => {
      if (err) throw err;
      console.log(directory);
      // Will print something similar to `/tmpabc123`.
      // A new temporary directory is created at the file system root
      // rather than *within* the /tmp directory.
    });
    
    // This method is *CORRECT*:
    import { sep } from 'node:path';
    mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
      if (err) throw err;
      console.log(directory);
      // Will print something similar to `/tmp/abc123`.
      // A new temporary directory is created within
      // the /tmp directory.
    });
    

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

    异步打开文件。详细信息请参考 POSIX open(2) 文档。

    mode 设置文件模式(权限和粘滞位),但仅在文件被创建时生效。在 Windows 上,只能操作写权限;详见 fs.chmod()

    回调接收两个参数 (err, fd)

    根据 命名文件、路径和命名空间 文档,某些字符(< > : " / \ | ? *)在 Windows 下是保留字符。在 NTFS 下,如果文件名包含冒号,Node.js 将打开一个文件系统流,如此 MSDN 页面所述。

    基于 fs.open() 的函数也表现出这种行为:fs.writeFile()fs.readFile() 等。

    fs.openAsBlob(path[, options])#

  • 返回: <Promise> 成功时兑现为 <Blob>

    返回一个数据由给定文件支持的 <Blob>

    创建 <Blob> 后不得修改该文件。任何修改都将导致读取 <Blob> 数据失败,并抛出 DOMException 错误。创建 Blob 时以及每次读取前,会对文件执行同步 stat 操作,以检测文件数据是否在磁盘上被修改。

    import { openAsBlob } from 'node:fs';
    
    const blob = await openAsBlob('the.file.txt');
    const ab = await blob.arrayBuffer();
    blob.stream();
    const { openAsBlob } = require('node:fs');
    
    (async () => {
      const blob = await openAsBlob('the.file.txt');
      const ab = await blob.arrayBuffer();
      blob.stream();
    })();
    
  • fs.opendir(path[, options], callback)#

  • callback <Function>
  • 异步打开一个目录。详细信息请参考 POSIX opendir(3) 文档。

    创建一个 <fs.Dir>,其中包含用于读取和清理目录的所有后续函数。

    encoding 选项设置打开目录及后续读取操作时 path 的编码。

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

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

    回调接收三个参数:(err, bytesRead, buffer)

    如果文件未被并发修改,当读取的字节数为零时,即到达文件末尾。

    如果此方法作为其 util.promisify() 版本调用,它返回一个包含 bytesReadbuffer 属性的 Object 的 Promise。

    fs.read() 方法从文件描述符 (fd) 指定的文件读取数据。length 参数表示 Node.js 将尝试从内核读取的最大字节数。但是,由于各种原因,实际读取的字节数 (bytesRead) 可能低于指定的 length

    例如:

    • 如果文件小于指定的 lengthbytesRead 将被设置为实际读取的字节数。
    • 如果文件在缓冲区填满之前遇到 EOF(文件结束),Node.js 将读取所有可用字节直到遇到 EOF,回调中的 bytesRead 参数将指示实际读取的字节数,该数值可能小于指定的 length
    • 如果文件位于慢速网络 filesystem 上,或者在读取过程中遇到任何其他问题,bytesRead 可能低于指定的 length

    因此,使用 fs.read() 时,检查 bytesRead 的值以确定实际上从文件中读取了多少字节非常重要。根据您的应用逻辑,如果需要最少数量的字节,您可能需要处理 bytesRead 小于指定的 length 的情况,例如通过在循环中包装读取调用。

    此行为类似于 POSIX preadv2 函数。

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

  • callback <Function>
  • fs.read() 函数类似,此版本采用一个可选的 options 对象。如果未指定 options 对象,它将使用上述默认值。

    fs.read(fd, buffer[, options], callback)#

  • callback <Function>
  • fs.read() 函数类似,此版本采用一个可选的 options 对象。如果未指定 options 对象,它将使用上述默认值。

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

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

    详细信息请参考 POSIX readdir(3) 文档。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定传递给回调的文件名所使用的字符编码。如果 encoding 设置为 'buffer',则返回的文件名将作为 <Buffer> 对象传递。

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

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

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

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

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

    如果未指定编码,则返回原始缓冲区。

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

    import { readFile } from 'node:fs';
    
    readFile('/etc/passwd', 'utf8', callback);
    

    当路径为目录时,fs.readFile()fs.readFileSync() 的行为因平台而异。在 macOS、Linux 和 Windows 上,将返回错误。在 FreeBSD 上,将返回目录内容的表示形式。

    import { readFile } from 'node:fs';
    
    // macOS, Linux, and Windows
    readFile('<directory>', (err, data) => {
      // => [Error: EISDIR: illegal operation on a directory, read <directory>]
    });
    
    //  FreeBSD
    readFile('<directory>', (err, data) => {
      // => null, <data>
    });
    

    可以使用 AbortSignal 中止正在进行的请求。如果请求被中止,回调将使用 AbortError 调用。

    import { readFile } from 'node:fs';
    
    const controller = new AbortController();
    const signal = controller.signal;
    readFile(fileInfo[0].name, { signal }, (err, buf) => {
      // ...
    });
    // When you want to abort the request
    controller.abort();
    

    fs.readFile() 函数缓冲整个文件。为了最小化内存成本,在可能的情况下,请优先通过 fs.createReadStream() 进行流式传输。

    中止正在进行的请求不会中止单个操作系统请求,而是中止 fs.readFile 执行的内部缓冲。

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

    fs.readFile() 方法异步将文件内容逐块读取到内存中,允许事件循环在每块数据之间进行轮转。这使得读取操作对可能使用底层 libuv 线程池的其他活动的影响较小,但也意味着将完整文件读取到内存中需要更长的时间。

    额外的读取开销在不同系统上可能会有很大差异,并且取决于正在读取的文件类型。如果文件类型不是常规文件(例如管道),并且 Node.js 无法确定实际文件大小,则每个读取操作将加载 64 KiB 的数据。对于常规文件,每次读取将处理 512 KiB 的数据。

    对于需要尽可能快地读取文件内容的应用程序,最好直接使用 fs.read(),并让应用程序代码自行管理读取文件的完整内容。

    Node.js GitHub 问题 #25741 提供了关于 fs.readFile() 在不同 Node.js 版本中针对多种文件大小的性能的更多信息和详细分析。

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

    读取由 path 引用的符号链接的内容。回调接收两个参数 (err, linkString)

    详细信息请参考 POSIX readlink(2) 文档。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定传递给回调的链接路径所使用的字符编码。如果 encoding 设置为 'buffer',则返回的链接路径将作为 <Buffer> 对象传递。

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

    fd 指定的文件中读取,并使用 readv() 写入一组 ArrayBufferView

    position 是从文件开头开始的偏移量,从中读取数据。如果 typeof position !== 'number',数据将从当前位置读取。

    回调将接收三个参数:errbytesReadbuffersbytesRead 是从文件中读取的字节数。

    如果此方法作为其 util.promisify() 版本调用,它返回一个包含 bytesReadbuffers 属性的 Object 的 Promise。

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

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

    规范路径名不一定是唯一的。硬链接和绑定挂载可以通过多个路径名公开一个文件系统实体。

    此函数表现得像 realpath(3),除了一些例外

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

    2. 符号链接的最大数量与平台无关,通常(远)高于原生 realpath(3) 实现所支持的数量。

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

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

    可选的 options 参数可以是一个指定编码的字符串,或者是一个包含 encoding 属性的对象,该属性指定了传递给回调函数的路径所使用的字符编码。如果 encoding 设置为 'buffer',则返回的路径将作为 <Buffer> 对象传递。

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

    如果路径不存在,将导致 ENOENT 错误。error.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.rename(oldPath, newPath, callback)#

    异步将 oldPath 处的文件重命名为 newPath 提供的路径名。如果 newPath 已经存在,它将被覆盖。如果 newPath 处存在一个目录,则会引发错误。除了可能的异常外,完成回调函数不会接收任何参数。

    另请参阅:rename(2)

    import { rename } from 'node:fs';
    
    rename('oldFile.txt', 'newFile.txt', (err) => {
      if (err) throw err;
      console.log('Rename complete!');
    });
    

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

    • path <string> | <Buffer> | <URL>
    • options <Object> 目前没有暴露任何选项。过去有 recursivemaxBusyTriesemfileWait 的选项,但它们已被弃用并移除。为了向后兼容,仍然接受 options 参数,但它不会被使用。
    • callback <Function>

    异步的 rmdir(2)。除了可能的异常外,完成回调函数不会接收任何参数。

    在文件(非目录)上使用 fs.rmdir() 在 Windows 上会导致 ENOENT 错误,在 POSIX 上会导致 ENOTDIR 错误。

    要获得类似于 Unix 命令 rm -rf 的行为,请使用带有 { recursive: true, force: true } 选项的 fs.rm()

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

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • force <boolean> 如果为 true,则在 path 不存在时忽略异常。 默认值: false
    • maxRetries <integer> 如果遇到 EBUSYEMFILEENFILEENOTEMPTYEPERM 错误,Node.js 将以线性退避等待的方式重试该操作,每次尝试的等待时间比上一次长 retryDelay 毫秒。此选项表示重试次数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 0
    • recursive <boolean> 如果为 true,则执行递归删除。在递归模式下,操作失败时会重试。默认值: false
    • retryDelay <integer> 重试之间等待的毫秒数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 100
  • callback <Function>
  • 异步删除文件和目录(模仿标准的 POSIX rm 工具)。除了可能的异常外,完成回调函数不会接收任何参数。

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

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • bigint <boolean> 返回的 <fs.Stats> 对象中的数值是否应为 bigint默认值: false
    • throwIfNoEntry <boolean> 如果没有文件系统条目存在时,是否抛出异常,而不是返回 undefined默认值: true
  • callback <Function>
  • 异步的 stat(2)。回调函数接收两个参数 (err, stats),其中 stats 是一个 <fs.Stats> 对象。

    如果发生错误,err.code 将是常见系统错误之一。

    fs.stat() 会跟随符号链接。要查看链接本身,请使用 fs.lstat()

    不建议在调用 fs.open()fs.readFile()fs.writeFile() 之前使用 fs.stat() 检查文件是否存在。相反,用户代码应该直接打开/读取/写入文件,并处理文件不可用时引发的错误。

    如果要在不进行后续操作的情况下检查文件是否存在,建议使用 fs.access()

    例如,给定以下目录结构

    - txtDir
    -- file.txt
    - app.js
    

    下一个程序将检查给定路径的状态

    import { stat } from 'node:fs';
    
    const pathsToCheck = ['./txtDir', './txtDir/file.txt'];
    
    for (let i = 0; i < pathsToCheck.length; i++) {
      stat(pathsToCheck[i], (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.statfs(path[, options], callback)#

  • callback <Function>
  • 异步的 statfs(2)。返回有关包含 path 的已挂载文件系统的信息。回调函数接收两个参数 (err, stats),其中 stats 是一个 <fs.StatFs> 对象。

    如果发生错误,err.code 将是常见系统错误之一。

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

    创建一个指向 target 的名为 path 的链接。除了可能的异常外,完成回调函数不会接收任何参数。

    详情请参阅 POSIX symlink(2) 文档。

    type 参数仅在 Windows 上可用,在其他平台上会被忽略。它可以设置为 'dir''file''junction'。如果 type 参数为 null,Node.js 将自动检测 target 类型并使用 'file''dir'。如果 target 不存在,将使用 'file'。Windows 软链接(junction points)要求目标路径必须是绝对路径。使用 'junction' 时,target 参数将自动规范化为绝对路径。NTFS 卷上的软链接只能指向目录。

    相对目标是相对于链接的父目录的。

    import { symlink } from 'node:fs';
    
    symlink('./mew', './mewtwo', callback);
    

    上述示例创建了一个名为 mewtwo 的符号链接,它指向同一目录下的 mew

    $ tree .
    .
    ├── mew
    └── mewtwo -> ./mew
    

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

    截断文件。除了可能的异常外,完成回调函数不会接收任何参数。也可以将文件描述符作为第一个参数传递。在这种情况下,会调用 fs.ftruncate()

    import { truncate } from 'node:fs';
    // Assuming that 'path/file.txt' is a regular file.
    truncate('path/file.txt', (err) => {
      if (err) throw err;
      console.log('path/file.txt was truncated');
    });
    const { truncate } = require('node:fs');
    // Assuming that 'path/file.txt' is a regular file.
    truncate('path/file.txt', (err) => {
      if (err) throw err;
      console.log('path/file.txt was truncated');
    });
    

    传递文件描述符的做法已弃用,未来可能会抛出错误。

    详情请参阅 POSIX truncate(2) 文档。

    fs.unlink(path, callback)#

    异步删除文件或符号链接。除了可能的异常外,完成回调函数不会接收任何参数。

    import { unlink } from 'node:fs';
    // Assuming that 'path/file.txt' is a regular file.
    unlink('path/file.txt', (err) => {
      if (err) throw err;
      console.log('path/file.txt was deleted');
    });
    

    fs.unlink() 不能用于目录(无论是否为空)。要删除目录,请使用 fs.rmdir()

    详情请参阅 POSIX unlink(2) 文档。

    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,则会抛出 Error

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

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

    第二个参数是可选的。如果 options 作为字符串提供,它指定 encoding。否则应将 options 作为对象传递。

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

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

    监听器回调函数附加到由 <fs.FSWatcher> 触发的 'change' 事件上,但这与 eventType'change' 值并不完全相同。

    如果传递了 signal,则中止相应的 AbortController 将关闭返回的 <fs.FSWatcher>

    注意事项#

    fs.watch API 在不同平台上的表现不完全一致,并且在某些情况下不可用。

    在 Windows 上,如果被监视的目录被移动或重命名,不会触发任何事件。删除被监视的目录时会报告 EPERM 错误。

    fs.watch API 不提供任何针对文件系统恶意行为的保护。例如,在 Windows 上,它通过监视目录的变化来实现,而不是监视特定文件。这允许替换文件,fs 会报告同名新文件的更改。

    可用性#

    此功能依赖于底层操作系统提供文件系统更改通知的方式。

    • 在 Linux 系统上,它使用 inotify(7)
    • 在 BSD 系统上,它使用 kqueue(2)
    • 在 macOS 上,它对文件使用 kqueue(2),对目录使用 FSEvents
    • 在 SunOS 系统(包括 Solaris 和 SmartOS)上,它使用 event ports
    • 在 Windows 系统上,此功能依赖于 ReadDirectoryChangesW
    • 在 AIX 系统上,此功能依赖于必须启用的 AHAFS
    • 在 IBM i 系统上,不支持此功能。

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

    仍然可以使用 fs.watchFile()(它使用 stat 轮询),但该方法速度较慢且不太可靠。

    Inode#

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

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

    Filename 参数#

    在回调函数中提供 filename 参数仅在 Linux、macOS、Windows 和 AIX 上受支持。即使在受支持的平台上,也不保证总是提供 filename。因此,不要假设回调函数中总是提供 filename 参数,并且如果它是 null,请准备好回退逻辑。

    import { watch } from 'node:fs';
    watch('somedir', (eventType, filename) => {
      console.log(`event type is: ${eventType}`);
      if (filename) {
        console.log(`filename provided: ${filename}`);
      } else {
        console.log('filename not provided');
      }
    });
    

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

  • listener <Function>
  • 返回:<fs.StatWatcher>
  • 监视 filename 的更改。回调 listener 将在每次访问文件时被调用。

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

    listener 接收两个参数:当前 stat 对象和前一个 stat 对象

    import { watchFile } from 'node:fs';
    
    watchFile('message.text', (curr, prev) => {
      console.log(`the current mtime is: ${curr.mtime}`);
      console.log(`the previous mtime was: ${prev.mtime}`);
    });
    

    这些 stat 对象是 fs.Stat 的实例。如果 bigint 选项为 true,这些对象中的数值将被指定为 BigInt

    要获知文件何时被修改(而不仅仅是被访问),需要比较 curr.mtimeMsprev.mtimeMs

    fs.watchFile 操作导致 ENOENT 错误时,它将调用一次监听器,并将所有字段清零(或对于日期字段,设为 Unix 纪元时间)。如果稍后创建了该文件,监听器将再次被调用,并带有最新的 stat 对象。这是 v0.10 以来的功能变更。

    使用 fs.watch()fs.watchFilefs.unwatchFile 更高效。在可能的情况下,应优先使用 fs.watch 而不是 fs.watchFilefs.unwatchFile

    fs.watchFile() 正在监视的文件消失并重新出现时,第二个回调事件(文件重新出现)中 previous 的内容将与第一个回调事件(文件消失)中 previous 的内容相同。

    这种情况发生在:

    • 文件被删除,随后被还原
    • 文件被重命名,然后第二次重命名回其原始名称

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

    buffer 写入 fd 指定的文件。

    offset 决定了要写入缓冲区的部分,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, buffer[, options], callback)#

  • callback <Function>
  • buffer 写入 fd 指定的文件。

    类似于上面的 fs.write 函数,此版本接收一个可选的 options 对象。如果没有指定 options 对象,它将默认为上述值。

    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 可以是字符串或缓冲区。

    file 为文件描述符时,其行为类似于直接调用 fs.write()(推荐)。请参阅下面关于使用文件描述符的注释。

    如果 data 是缓冲区,则忽略 encoding 选项。

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

    import { writeFile } from 'node:fs';
    import { Buffer } from 'node:buffer';
    
    const data = new Uint8Array(Buffer.from('Hello Node.js'));
    writeFile('message.txt', data, (err) => {
      if (err) throw err;
      console.log('The file has been saved!');
    });
    

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

    import { writeFile } from 'node:fs';
    
    writeFile('message.txt', 'Hello Node.js', 'utf8', callback);
    

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

    fs.readFile 类似,fs.writeFile 是一种便捷方法,它在内部执行多次 write 调用以写入传递给它的缓冲区。对于性能敏感的代码,请考虑使用 fs.createWriteStream()

    可以使用 <AbortSignal> 来取消 fs.writeFile()。取消操作是“尽力而为”的,很可能仍会有部分数据被写入。

    import { writeFile } from 'node:fs';
    import { Buffer } from 'node:buffer';
    
    const controller = new AbortController();
    const { signal } = controller;
    const data = new Uint8Array(Buffer.from('Hello Node.js'));
    writeFile('message.txt', data, { signal }, (err) => {
      // When a request is aborted - the callback is called with an AbortError
    });
    // When the request should be aborted
    controller.abort();
    

    中止正在进行的请求不会中止单个操作系统请求,而是中止 fs.writeFile 执行的内部缓冲。

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

    file 为文件描述符时,其行为几乎等同于直接调用 fs.write(),如下所示:

    import { write } from 'node:fs';
    import { Buffer } from 'node:buffer';
    
    write(fd, Buffer.from(data, options.encoding), callback);
    

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

    其含义是混淆的常见来源。在使用文件描述符的情况下,文件不会被替换!数据不一定会从文件开头开始写入,文件原始数据可能会保留在刚写入数据的前面和/或后面。

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

    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 上,当文件以追加模式打开时,定位写入无法工作。内核会忽略位置参数,始终将数据追加到文件末尾。

    同步 API#

    同步 API 同步执行所有操作,阻塞事件循环直到操作完成或失败。

    fs.accessSync(path[, mode])#

    同步测试用户对 path 指定的文件或目录的权限。mode 参数是一个可选整数,用于指定要执行的访问权限检查。mode 应为 fs.constants.F_OK 的值,或由 fs.constants.R_OKfs.constants.W_OKfs.constants.X_OK 中任意项按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。检查 文件访问常量 以获取 mode 的可能值。

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

    import { accessSync, constants } from 'node:fs';
    
    try {
      accessSync('etc/passwd', constants.R_OK | constants.W_OK);
      console.log('can read/write');
    } catch (err) {
      console.error('no access!');
    }
    

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

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

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

    import { appendFileSync } from 'node:fs';
    
    try {
      appendFileSync('message.txt', 'data to append');
      console.log('The "data to append" was appended to file!');
    } catch (err) {
      /* Handle the error */
    }
    

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

    import { appendFileSync } from 'node:fs';
    
    appendFileSync('message.txt', 'data to append', 'utf8');
    

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

    import { openSync, closeSync, appendFileSync } from 'node:fs';
    
    let fd;
    
    try {
      fd = openSync('message.txt', 'a');
      appendFileSync(fd, 'data to append', 'utf8');
    } catch (err) {
      /* Handle the error */
    } finally {
      if (fd !== undefined)
        closeSync(fd);
    }
    

    fs.chmodSync(path, mode)#

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

    详细信息请参考 POSIX chmod(2) 文档。

    fs.chownSync(path, uid, gid)#

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

    详细信息请参考 POSIX chown(2) 文档。

    fs.closeSync(fd)#

    关闭文件描述符。返回 undefined

    对当前正在通过任何其他 fs 操作使用的任何文件描述符 (fd) 调用 fs.closeSync() 可能会导致未定义的行为。

    详细信息请参考 POSIX close(2) 文档。

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

    同步将 src 复制到 dest。默认情况下,如果 dest 已存在则会被覆盖。返回 undefined。Node.js 不保证复制操作的原子性。如果目标文件已打开以进行写入后发生错误,Node.js 将尝试删除目标文件。

    mode 是一个可选整数,指定复制操作的行为。可以创建一个由两个或多个值按位 OR 组成的掩码(例如 fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE)。

    • fs.constants.COPYFILE_EXCL:如果 dest 已存在,则复制操作将失败。
    • fs.constants.COPYFILE_FICLONE:复制操作将尝试创建写时复制 (copy-on-write) 再链接 (reflink)。如果平台不支持写时复制,则使用回退复制机制。
    • fs.constants.COPYFILE_FICLONE_FORCE:复制操作将尝试创建写时复制再链接。如果平台不支持写时复制,则操作将失败。
    import { copyFileSync, constants } from 'node:fs';
    
    // destination.txt will be created or overwritten by default.
    copyFileSync('source.txt', 'destination.txt');
    console.log('source.txt was copied to destination.txt');
    
    // By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
    copyFileSync('source.txt', 'destination.txt', constants.COPYFILE_EXCL);
    

    fs.cpSync(src, dest[, options])#

    • src <string> | <URL> 要复制的源路径。
    • dest <string> | <URL> 要复制到的目标路径。
    • options <Object>
    • dereference <boolean> 取消引用符号链接。默认值: false
    • errorOnExist <boolean>forcefalse 且目标存在时,抛出错误。默认值: false
    • filter <Function> 用于过滤已复制文件/目录的函数。返回 true 以复制该项目,返回 false 以忽略它。忽略目录时,其所有内容也将被跳过。默认值: undefined
      • src <string> 要复制的源路径。
      • dest <string> 要复制到的目标路径。
      • 返回:<boolean> 任何可强制转换为 boolean 的非 Promise 值。
    • force <boolean> 覆盖现有文件或目录。如果您将其设置为 false 且目标存在,复制操作将忽略错误。使用 errorOnExist 选项更改此行为。默认值: true
    • mode <integer> 复制操作的修饰符。默认值: 0。请参阅 fs.copyFileSync()mode 标志。
    • preserveTimestamps <boolean> 当为 true 时,将保留来自 src 的时间戳。默认值: false
    • recursive <boolean> 递归复制目录。默认值: false
    • verbatimSymlinks <boolean> 当为 true 时,将跳过符号链接的路径解析。默认值: false

    同步将整个目录结构从 src 复制到 dest,包括子目录和文件。

    将目录复制到另一个目录时,不支持 glob 模式,且行为类似于 cp dir1/ dir2/

    fs.existsSync(path)#

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

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

    fs.exists() 已弃用,但 fs.existsSync() 没有。fs.exists()callback 参数接收的参数与其他 Node.js 回调函数不一致。fs.existsSync() 不使用回调。

    import { existsSync } from 'node:fs';
    
    if (existsSync('/etc/passwd'))
      console.log('The path exists.');
    

    fs.fchmodSync(fd, mode)#

    设置文件的权限。返回 undefined

    详细信息请参考 POSIX fchmod(2) 文档。

    fs.fchownSync(fd, uid, gid)#

    设置文件的所有者。返回 undefined

    详细信息请参考 POSIX fchown(2) 文档。

    fs.fdatasyncSync(fd)#

    强制将与文件关联的所有当前已排队的 I/O 操作提交到操作系统的同步 I/O 完成状态。详细信息请参阅 POSIX fdatasync(2) 文档。返回 undefined

    fs.fstatSync(fd[, options])#

  • 返回:<fs.Stats>
  • 检索文件描述符的 <fs.Stats>

    详细信息请参考 POSIX fstat(2) 文档。

    fs.fsyncSync(fd)#

    请求将打开的文件描述符的所有数据刷新到存储设备。具体实现取决于操作系统和设备。详细信息请参阅 POSIX fsync(2) 文档。返回 undefined

    fs.ftruncateSync(fd[, len])#

    截断文件描述符。返回 undefined

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

    fs.futimesSync(fd, atime, mtime)#

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

    fs.globSync(pattern[, options])#

    • pattern <string> | <string[]>
    • options <Object>
    • cwd <string> | <URL> 当前工作目录。默认值: process.cwd()
    • exclude <Function> | <string[]> 用于过滤文件/目录的函数或要排除的 glob 模式列表。如果提供了函数,返回 true 以排除项目,返回 false 以包含它。 默认值: undefined
    • withFileTypes <boolean> 如果 glob 应将路径作为 Dirent 返回,则为 true,否则为 false默认值: false
  • 返回:<string[]> 符合模式的文件路径。
  • import { globSync } from 'node:fs';
    
    console.log(globSync('**/*.js'));
    const { globSync } = require('node:fs');
    
    console.log(globSync('**/*.js'));
    

    fs.lchmodSync(path, mode)#

    稳定性:0 - 已弃用

    更改符号链接的权限。返回 undefined

    此方法仅在 macOS 上实现。

    详细信息请参考 POSIX lchmod(2) 文档。

    fs.lchownSync(path, uid, gid)#

    设置路径的所有者。返回 undefined

    详情请参阅 POSIX lchown(2) 文档。

    fs.lutimesSync(path, atime, mtime)#

    更改 path 引用的符号链接的文件系统时间戳。返回 undefined,或者在参数不正确或操作失败时抛出异常。这是 fs.lutimes() 的同步版本。

    fs.linkSync(existingPath, newPath)#

    existingPath 创建到 newPath 的新链接。详细信息请参阅 POSIX link(2) 文档。返回 undefined

    fs.lstatSync(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • bigint <boolean> 返回的 <fs.Stats> 对象中的数值是否应为 bigint默认值: false
    • throwIfNoEntry <boolean> 如果没有文件系统条目存在时,是否抛出异常,而不是返回 undefined默认值: true
  • 返回:<fs.Stats>
  • 检索 path 所引用的符号链接的 <fs.Stats>

    详细信息请参考 POSIX lstat(2) 文档。

    fs.mkdirSync(path[, options])#

    同步创建目录。返回 undefined,或者如果 recursivetrue,则返回第一个创建的目录路径。这是 fs.mkdir() 的同步版本。

    详细信息请参考 POSIX mkdir(2) 文档。

    fs.mkdtempSync(prefix[, options])#

    返回创建的目录路径。

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

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定使用的字符编码。

    fs.mkdtempDisposableSync(prefix[, options])#

    返回一个可清理对象,其 path 属性保存了已创建的目录路径。当对象被处理(disposed)时,如果目录仍然存在,它及其内容将被移除。如果无法删除目录,处理操作将抛出错误。该对象具有一个执行相同任务的 remove() 方法。

    详细信息,请参阅 fs.mkdtemp() 的文档。

    不存在基于回调的 API 版本,因为它设计用于 using 语法。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定使用的字符编码。

    fs.opendirSync(path[, options])#

  • 返回:<fs.Dir>
  • 同步打开目录。请参阅 opendir(3)

    创建一个 <fs.Dir>,其中包含用于读取和清理目录的所有后续函数。

    encoding 选项设置打开目录及后续读取操作时 path 的编码。

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

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

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

    fs.readdirSync(path[, options])#

    读取目录内容。

    详细信息请参考 POSIX readdir(3) 文档。

    可选的 options 参数可以是一个指定编码的字符串,或者是一个包含 encoding 属性的对象,该属性指定了返回文件名所使用的字符编码。如果 encoding 设置为 'buffer',则返回的文件名将作为 <Buffer> 对象传递。

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

    fs.readFileSync(path[, options])#

    返回 path 的内容。

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

    如果指定了 encoding 选项,则该函数返回字符串。否则返回缓冲区。

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

    import { readFileSync } from 'node:fs';
    
    // macOS, Linux, and Windows
    readFileSync('<directory>');
    // => [Error: EISDIR: illegal operation on a directory, read <directory>]
    
    //  FreeBSD
    readFileSync('<directory>'); // => <data>
    

    fs.readlinkSync(path[, options])#

    返回符号链接的字符串值。

    详细信息请参考 POSIX readlink(2) 文档。

    可选的 options 参数可以是一个指定编码的字符串,或者一个包含 encoding 属性的对象,用于指定返回的链接路径所使用的字符编码。如果 encoding 设置为 'buffer',则返回的链接路径将作为 <Buffer> 对象传递。

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

    返回读取的 bytesRead(字节数)。

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

    fs.readSync(fd, buffer[, options])#

  • 返回: <number>
  • 返回读取的 bytesRead(字节数)。

    类似于上面的 fs.readSync 函数,此版本接收一个可选的 options 对象。如果没有指定 options 对象,它将默认为上述值。

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

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

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

    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.renameSync(oldPath, newPath)#

    将文件从 oldPath 重命名为 newPath。返回 undefined

    详情请参阅 POSIX rename(2) 文档。

    fs.rmdirSync(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object> 目前没有暴露任何选项。过去有 recursivemaxBusyTriesemfileWait 的选项,但它们已被弃用并移除。为了向后兼容,仍然接受 options 参数,但它不会被使用。

    同步的 rmdir(2)。返回 undefined

    在文件(非目录)上使用 fs.rmdirSync() 在 Windows 上会导致 ENOENT 错误,在 POSIX 上会导致 ENOTDIR 错误。

    要获得类似于 Unix 命令 rm -rf 的行为,请使用带有 { recursive: true, force: true } 选项的 fs.rmSync()

    fs.rmSync(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • force <boolean> 如果为 true,则在 path 不存在时忽略异常。 默认值: false
    • maxRetries <integer> 如果遇到 EBUSYEMFILEENFILEENOTEMPTYEPERM 错误,Node.js 将以线性退避等待的方式重试该操作,每次尝试的等待时间比上一次长 retryDelay 毫秒。此选项表示重试次数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 0
    • recursive <boolean> 如果为 true,则执行递归目录移除。在递归模式下,失败的操作会进行重试。 默认值: false
    • retryDelay <integer> 重试之间等待的毫秒数。如果 recursive 选项不为 true,则忽略此选项。 默认值: 100

    同步删除文件和目录(模仿标准的 POSIX rm 工具)。返回 undefined

    fs.statSync(path[, options])#

    • path <string> | <Buffer> | <URL>
    • options <Object>
    • bigint <boolean> 返回的 <fs.Stats> 对象中的数值是否应为 bigint默认值: false
    • throwIfNoEntry <boolean> 如果没有文件系统条目存在时,是否抛出异常,而不是返回 undefined默认值: true
  • 返回:<fs.Stats>
  • 检索路径的 <fs.Stats>

    fs.statfsSync(path[, options])#

  • 返回:<fs.StatFs>
  • 同步的 statfs(2)。返回有关包含 path 的已挂载文件系统的信息。

    如果发生错误,err.code 将是常见系统错误之一。

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

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

    fs.truncateSync(path[, len])#

    截断文件。返回 undefined。也可以将文件描述符作为第一个参数传递。在这种情况下,会调用 fs.ftruncateSync()

    传递文件描述符的做法已弃用,未来可能会抛出错误。

    fs.unlinkSync(path)#

    同步的 unlink(2)。返回 undefined

    fs.utimesSync(path, atime, mtime)#

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

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

    mode 选项仅影响新创建的文件。有关详细信息,请参见 fs.open()

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

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

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

    fs.writeSync(fd, buffer[, options])#

  • 返回:<number> 写入的字节数。

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

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

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

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

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

    通用对象#

    通用对象由所有文件系统 API 变体(Promise、回调和同步)共享。

    类:fs.Dir#

    表示目录流的类。

    fs.opendir()fs.opendirSync()fsPromises.opendir() 创建。

    import { opendir } from 'node:fs/promises';
    
    try {
      const dir = await opendir('./');
      for await (const dirent of dir)
        console.log(dirent.name);
    } catch (err) {
      console.error(err);
    }
    

    使用异步迭代器时,<fs.Dir> 对象将在迭代器退出后自动关闭。

    dir.close()#

    异步关闭目录的基础资源句柄。后续读取将导致错误。

    返回一个 Promise,该 Promise 将在资源关闭后完成。

    dir.close(callback)#

    异步关闭目录的基础资源句柄。后续读取将导致错误。

    callback 将在资源句柄关闭后被调用。

    dir.closeSync()#

    同步关闭目录的基础资源句柄。后续读取将导致错误。

    dir.path#

    此目录的只读路径,即传递给 fs.opendir()fs.opendirSync()fsPromises.opendir() 的路径。

    dir.read()#

    通过 readdir(3) 异步读取下一个目录条目,作为 <fs.Dirent>

    返回一个 Promise,该 Promise 将使用 <fs.Dirent> 完成,如果没有更多目录条目可读取,则使用 null 完成。

    由此函数返回的目录条目没有特定的顺序,由操作系统的底层目录机制提供。在迭代目录时添加或删除的条目可能不会包含在迭代结果中。

    dir.read(callback)#

    通过 readdir(3) 异步读取下一个目录条目,作为 <fs.Dirent>

    读取完成后,callback 将使用 <fs.Dirent> 调用,如果没有更多目录条目可读取,则使用 null 调用。

    由此函数返回的目录条目没有特定的顺序,由操作系统的底层目录机制提供。在迭代目录时添加或删除的条目可能不会包含在迭代结果中。

    dir.readSync()#

    同步读取下一个目录条目作为 <fs.Dirent>。详细信息请参阅 POSIX readdir(3) 文档。

    如果没有更多目录条目可读取,将返回 null

    由此函数返回的目录条目没有特定的顺序,由操作系统的底层目录机制提供。在迭代目录时添加或删除的条目可能不会包含在迭代结果中。

    dir[Symbol.asyncIterator]()#

    异步迭代目录,直到所有条目都被读取。详细信息请参阅 POSIX readdir(3) 文档。

    由此异步迭代器返回的条目始终是 <fs.Dirent>dir.read() 中的 null 情况在内部处理。

    请参阅 <fs.Dir> 获取示例。

    由此迭代器返回的目录条目没有特定的顺序,由操作系统的底层目录机制提供。在迭代目录时添加或删除的条目可能不会包含在迭代结果中。

    dir[Symbol.asyncDispose]()#

    如果目录句柄已打开,则调用 dir.close(),并返回一个在处理完成时完成的 Promise。

    dir[Symbol.dispose]()#

    如果目录句柄已打开,则调用 dir.closeSync(),并返回 undefined

    类:fs.Dirent#

    目录条目的表示,可以是目录内的文件或子目录,由从 <fs.Dir> 中读取返回。目录条目是文件名和文件类型对的组合。

    此外,当使用设置了 truewithFileTypes 选项调用 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 决定。

    dirent.parentPath#

    <fs.Dirent> 对象引用的文件的父目录路径。

    类:fs.FSWatcher#

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

    所有 <fs.FSWatcher> 对象在修改特定监视文件时都会发出 'change' 事件。

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

    当被监视的目录或文件发生更改时发出。详情请参阅 fs.watch()

    根据操作系统支持情况,可能不会提供 filename 参数。如果提供了 filename,当使用 encoding 选项设置为 'buffer' 调用 fs.watch() 时,它将作为 <Buffer> 提供,否则 filename 将是一个 UTF-8 字符串。

    import { watch } from 'node:fs';
    // Example when handled through fs.watch() listener
    watch('./tmp', { encoding: 'buffer' }, (eventType, filename) => {
      if (filename) {
        console.log(filename);
        // Prints: <Buffer ...>
      }
    });
    
    事件: 'close'#

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

    事件:'error'#

    当监视文件时发生错误时发出。出错的 <fs.FSWatcher> 对象在事件处理器中不再可用。

    watcher.close()#

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

    watcher.ref()#

    调用时,请求 Node.js 事件循环在 <fs.FSWatcher> 处于活动状态期间退出。多次调用 watcher.ref() 不会产生影响。

    默认情况下,所有 <fs.FSWatcher> 对象都是“ref'ed”,因此除非之前调用过 watcher.unref(),否则通常不需要调用 watcher.ref()

    watcher.unref()#

    调用时,活动的 <fs.FSWatcher> 对象将不再需要保持 Node.js 事件循环处于活动状态。如果此时没有其他保持事件循环运行的活动,进程可能会在调用 <fs.FSWatcher> 对象的回调函数之前退出。多次调用 watcher.unref() 不会产生影响。

    类:fs.StatWatcher#

    成功调用 fs.watchFile() 方法将返回一个新的 <fs.StatWatcher> 对象。

    watcher.ref()#

    调用时,请求 Node.js 事件循环在 <fs.StatWatcher> 处于活动状态期间退出。多次调用 watcher.ref() 不会产生影响。

    默认情况下,所有 <fs.StatWatcher> 对象都是“ref'ed”,因此除非之前调用过 watcher.unref(),否则通常不需要调用 watcher.ref()

    watcher.unref()#

    调用时,活动的 <fs.StatWatcher> 对象将不再需要保持 Node.js 事件循环处于活动状态。如果此时没有其他保持事件循环运行的活动,进程可能会在调用 <fs.StatWatcher> 对象的回调函数之前退出。多次调用 watcher.unref() 不会产生影响。

    类:fs.ReadStream#

    <fs.ReadStream> 实例不能直接构造。它们使用 fs.createReadStream() 函数创建并返回。

    事件:'close'#

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

    事件:'open'#

    <fs.ReadStream> 的文件描述符已打开时发出。

    事件:'ready'#

    <fs.ReadStream> 准备好使用时发出。

    'open' 之后立即触发。

    readStream.bytesRead#

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

    readStream.path#

    流从中读取的文件的路径,如 fs.createReadStream() 的第一个参数中所指定。如果 path 作为字符串传递,则 readStream.path 将是一个字符串。如果 path 作为 <Buffer> 传递,则 readStream.path 将是一个 <Buffer>。如果指定了 fd,则 readStream.path 将为 undefined

    readStream.pending#

    如果基础文件尚未打开(即在发出 'ready' 事件之前),此属性为 true

    类:fs.Stats#

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

    fs.stat()fs.lstat()fs.fstat() 及其同步对应方法返回的对象属于此类型。如果传递给这些方法的 options 中的 bigint 为 true,则数值将为 bigint 而不是 number,并且该对象将包含后缀为 Ns 的纳秒级精度属性。Stat 对象不应使用 new 关键字直接创建。

    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 版本

    BigIntStats {
      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,
      atimeNs: 1318289051000000000n,
      mtimeNs: 1318289051000000000n,
      ctimeNs: 1318289051000000000n,
      birthtimeNs: 1318289051000000000n,
      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

    如果 <fs.Stats> 对象是通过在符号链接上调用 fs.lstat() 获得的(该链接解析为目录),则此方法将返回 false。这是因为 fs.lstat() 返回的是关于符号链接本身的信息,而不是它所解析路径的信息。

    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#

    文件的文件系统特定“Inode”编号。

    stats.mode#

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

    stats.nlink#

    文件存在的硬链接数。

    stats.uid#

    文件所有者的数字用户标识符(POSIX)。

    stats.gid#

    文件所属组的数字组标识符(POSIX)。

    stats.rdev#

    如果文件代表设备,则为数字设备标识符。

    stats.size#

    文件大小(字节)。

    如果底层文件系统不支持获取文件大小,则此值为 0

    stats.blksize#

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

    stats.blocks#

    为此文件分配的块数。

    stats.atimeMs#

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

    stats.mtimeMs#

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

    stats.ctimeMs#

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

    stats.birthtimeMs#

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

    stats.atimeNs#

    仅在传递 bigint: true 到生成该对象的方法时出现。指示上次访问此文件的时间戳,以 POSIX 纪元以来的纳秒数表示。

    stats.mtimeNs#

    仅在传递 bigint: true 到生成该对象的方法时出现。指示上次修改此文件的时间戳,以 POSIX 纪元以来的纳秒数表示。

    stats.ctimeNs#

    仅在传递 bigint: true 到生成该对象的方法时出现。指示上次更改文件状态的时间戳,以 POSIX 纪元以来的纳秒数表示。

    stats.birthtimeNs#

    仅在传递 bigint: true 到生成该对象的方法时出现。指示此文件创建时间的时间戳,以 POSIX 纪元以来的纳秒数表示。

    stats.atime#

    指示上次访问此文件的时间戳。

    stats.mtime#

    指示上次修改此文件的时间戳。

    stats.ctime#

    指示上次更改文件状态的时间戳。

    stats.birthtime#

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

    Stat 时间值#

    atimeMsmtimeMsctimeMsbirthtimeMs 属性是保存相应时间(毫秒)的数值。它们的精度取决于平台。当传递 bigint: true 到生成对象的方法时,这些属性将为 bigints,否则它们将为 numbers

    atimeNsmtimeNsctimeNsbirthtimeNs 属性是保存相应时间(纳秒)的 bigints。它们仅在传递 bigint: true 到生成对象的方法时出现。它们的精度取决于平台。

    atimemtimectimebirthtime 是各种时间的 Date 对象替代表示。Date 和数字值之间没有关联。分配新的数字值或修改 Date 值不会反映在相应的替代表示中。

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

    • atime “访问时间”:上次访问文件数据的时间。由 mknod(2)utimes(2)read(2) 系统调用更改。
    • mtime “修改时间”:上次修改文件数据的时间。由 mknod(2)utimes(2)write(2) 系统调用更改。
    • ctime "Change Time"(状态更改时间):文件状态最后一次更改的时间(inode 数据修改)。由 chmod(2)chown(2)link(2)mknod(2)rename(2)unlink(2)utimes(2)read(2)write(2) 系统调用所更改。
    • birthtime "Birth Time"(创建时间):文件创建时间。在文件创建时设置一次。在不支持创建时间的文件系统上,该字段可能保存为 ctime1970-01-01T00:00Z(即 Unix 纪元时间戳 0)。在这种情况下,该值可能大于 atimemtime。在 Darwin 和其他 FreeBSD 变体上,如果使用 utimes(2) 系统调用将 atime 显式设置为早于当前 birthtime 的值,也会进行更新。

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

    类:fs.StatFs#

    提供有关已挂载文件系统的信息。

    fs.statfs() 及其同步对应方法返回的对象均为该类型。如果传递给这些方法的 options 中的 biginttrue,则数值将为 bigint 而非 number

    StatFs {
      type: 1397114950,
      bsize: 4096,
      blocks: 121938943,
      bfree: 61058895,
      bavail: 61058895,
      files: 999,
      ffree: 1000000
    }
    

    bigint 版本

    StatFs {
      type: 1397114950n,
      bsize: 4096n,
      blocks: 121938943n,
      bfree: 61058895n,
      bavail: 61058895n,
      files: 999n,
      ffree: 1000000n
    }
    
    statfs.bavail#

    非特权用户可用的空闲块数。

    statfs.bfree#

    文件系统中的空闲块数。

    statfs.blocks#

    文件系统中的数据块总数。

    statfs.bsize#

    最优传输块大小。

    statfs.ffree#

    文件系统中的空闲文件节点(inode)数。

    statfs.files#

    文件系统中的文件节点总数。

    statfs.type#

    文件系统类型。

    类:fs.Utf8Stream#

    稳定性:1 - 实验性

    一种优化的 UTF-8 流写入器,允许按需刷新所有内部缓冲区。它能正确处理 EAGAIN 错误,允许进行自定义(例如,如果磁盘繁忙则丢弃内容)。

    事件:'close'#

    当流完全关闭时触发 'close' 事件。

    事件: 'drain'#

    当内部缓冲区已充分清空并允许继续写入时触发 'drain' 事件。

    事件:'drop'#

    当达到最大长度且数据无法被写入时触发 'drop' 事件。被丢弃的数据将作为第一个参数传递给事件处理程序。

    事件: 'error'#

    当发生错误时触发 'error' 事件。

    事件: 'finish'#

    当流已结束且所有数据已刷新到底层文件时触发 'finish' 事件。

    事件:'ready'#

    当流准备好接受写入时触发 'ready' 事件。

    事件:'write'#

    当写入操作完成时触发 'write' 事件。写入的字节数作为第一个参数传递给事件处理程序。

    new fs.Utf8Stream([options])#
    • options <Object>
    • append<boolean> 将写入内容追加到目标文件而不是截断它。默认值true
    • contentMode<string> 可发送给写入函数的类型,支持的值为 'utf8''buffer'默认值'utf8'
    • dest<string> 待写入文件的路径(模式由 append 选项控制)。
    • fd<number> 文件描述符,由 fs.open()fs.openSync() 返回。
    • fs<Object> 具有与 fs 模块相同 API 的对象,适用于模拟、测试或自定义流的行为。
    • fsync<boolean> 每次写入完成时执行一次 fs.fsyncSync()
    • maxLength<number> 内部缓冲区的最大长度。如果写入操作导致缓冲区超过 maxLength,写入的数据将被丢弃,并触发包含被丢弃数据的 drop 事件。
    • maxWrite<number> 可写入的最大字节数;默认值16384
    • minLength<number> 触发刷新前内部缓冲区所需的最小长度。
    • mkdir<boolean> 如果为 true,则确保 dest 文件的目录存在。默认值false
    • mode<number> | <string> 指定创建文件的模式(参见 fs.open())。
    • periodicFlush<number> 每隔 periodicFlush 毫秒调用一次 flush。
    • retryEAGAIN <Function>write()writeSync()flushSync() 遇到 EAGAINEBUSY 错误时调用的函数。如果返回值为 true,则会重试操作,否则将抛出错误。err 是导致调用该函数的错误,writeBufferLen 是已写入的缓冲区长度,remainingBufferLen 是流未尝试写入的剩余缓冲区长度。
    • sync<boolean> 同步执行写入。
    utf8Stream.append#
    • <boolean> 流是追加到文件还是截断文件。
    utf8Stream.contentMode#
    • <string> 可写入流的数据类型。支持的值为 'utf8''buffer'默认值'utf8'
    utf8Stream.destroy()#

    立即关闭流,不刷新内部缓冲区。

    utf8Stream.end()#

    优雅地关闭流,在关闭前刷新内部缓冲区。

    utf8Stream.fd#
    • <number> 正在写入的文件描述符。
    utf8Stream.file#
    utf8Stream.flush(callback)#

    如果写入尚未进行,将当前缓冲区写入文件。如果 minLength 为零或已在写入中,则不执行任何操作。

    utf8Stream.flushSync()#

    同步刷新缓冲数据。这是一个昂贵的操作。

    utf8Stream.fsync#
    • <boolean> 流是否在每次写入操作后执行 fs.fsyncSync()
    utf8Stream.maxLength#
    • <number> 内部缓冲区的最大长度。如果写入导致缓冲区超过 maxLength,则写入数据会被丢弃并触发 drop 事件。
    utf8Stream.minLength#
    • <number> 触发刷新前所需的最小缓冲区长度。
    utf8Stream.mkdir#
    • <boolean> 流是否应确保 dest 文件目录存在。如果为 true,则在目录不存在时创建它。默认值false
    utf8Stream.mode#
    utf8Stream.periodicFlush#
    • <number> 两次刷新之间的毫秒数。如果设为 0,则不执行周期性刷新。
    utf8Stream.reopen(file)#

    就地重新打开文件,适用于日志轮转。

    utf8Stream.sync#
    • <boolean> 流是同步还是异步写入。
    utf8Stream.write(data)#

    如果创建流时 options.contentMode 设为 'utf8',则 data 参数必须是字符串。如果 contentMode 设为 'buffer',则 data 参数必须是 <Buffer>

    utf8Stream.writing#
    • <boolean> 流是否当前正在将数据写入文件。
    utf8Stream[Symbol.dispose]()#

    调用 utf8Stream.destroy()

    类:fs.WriteStream#

    <fs.WriteStream> 的实例不能直接构造。它们通过 fs.createWriteStream() 函数创建并返回。

    事件:'close'#

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

    事件:'open'#

    <fs.WriteStream> 的文件打开时触发。

    事件:'ready'#

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

    'open' 之后立即触发。

    writeStream.bytesWritten#

    迄今已写入的字节数。不包括仍在排队等待写入的数据。

    writeStream.close([callback])#

    关闭 writeStream。可选择接受一个在 writeStream 关闭后执行的回调函数。

    writeStream.path#

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

    writeStream.pending#

    如果基础文件尚未打开(即在发出 'ready' 事件之前),此属性为 true

    fs.constants#

    返回包含文件系统操作常用常量的一个对象。

    文件系统(FS)常量#

    以下常量由 fs.constantsfsPromises.constants 导出。

    并非每个常量在所有操作系统上都可用;这在 Windows 上尤为重要,许多 POSIX 特有的定义在 Windows 上不可用。对于可移植应用程序,建议在使用前检查它们是否存在。

    要同时使用多个常量,请使用按位或 | 运算符。

    示例

    import { open, constants } from 'node:fs';
    
    const {
      O_RDWR,
      O_CREAT,
      O_EXCL,
    } = constants;
    
    open('/path/to/my/file', O_RDWR | O_CREAT | O_EXCL, (err, fd) => {
      // ...
    });
    
    文件访问常量#

    以下常量旨在作为 mode 参数传递给 fsPromises.access()fs.access()fs.accessSync()

    常量 描述
    F_OK 标识文件对调用进程可见的标志。这有助于确定文件是否存在,但无法说明 rwx 权限。如果未指定模式,则为默认值。
    R_OK 标识文件可由调用进程读取的标志。
    W_OK 标识文件可由调用进程写入的标志。
    X_OK 标识文件可由调用进程执行的标志。这在 Windows 上无效(表现得像 fs.constants.F_OK)。

    这些定义在 Windows 上也可用。

    文件复制常量#

    以下常量旨在与 fs.copyFile() 一起使用。

    常量 描述
    COPYFILE_EXCL 如果存在,则当目标路径已存在时,复制操作将失败并报错。
    COPYFILE_FICLONE 如果存在,则复制操作将尝试创建写时复制(copy-on-write)引用链接。如果底层平台不支持写时复制,则使用备用复制机制。
    COPYFILE_FICLONE_FORCE 如果存在,则复制操作将尝试创建写时复制引用链接。如果底层平台不支持,则操作将失败并报错。

    这些定义在 Windows 上也可用。

    文件打开常量#

    以下常量旨在与 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 标识在可能时以非阻塞模式打开文件的标志。
    UV_FS_O_FILEMAP 设置后,使用内存文件映射来访问文件。该标志仅在 Windows 操作系统上可用。在其他操作系统上会被忽略。

    在 Windows 上,仅支持 O_APPENDO_CREATO_EXCLO_RDONLYO_RDWRO_TRUNCO_WRONLYUV_FS_O_FILEMAP

    文件类型常量#

    以下常量旨在与 <fs.Stats> 对象的 mode 属性配合使用,以确定文件类型。

    常量 描述
    S_IFMT 用于提取文件类型代码的位掩码。
    S_IFREG 常规文件的文件类型常量。
    S_IFDIR 目录的文件类型常量。
    S_IFCHR 字符设备文件的文件类型常量。
    S_IFBLK 块设备文件的文件类型常量。
    S_IFIFO FIFO/管道的文件类型常量。
    S_IFLNK 符号链接的文件类型常量。
    S_IFSOCK 套接字(socket)的文件类型常量。

    在 Windows 上,仅支持 S_IFCHRS_IFDIRS_IFLNKS_IFMTS_IFREG

    文件模式常量#

    以下常量旨在与 <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 其他用户可执行的文件模式。

    在 Windows 上,仅支持 S_IRUSRS_IWUSR

    注意事项#

    回调与基于 Promise 操作的顺序#

    由于底层线程池是异步执行的,因此使用回调或基于 Promise 的方法时,不保证操作顺序。

    例如,以下代码容易出错,因为 fs.stat() 操作可能在 fs.rename() 操作之前完成。

    const fs = require('node:fs');
    
    fs.rename('/tmp/hello', '/tmp/world', (err) => {
      if (err) throw err;
      console.log('renamed complete');
    });
    fs.stat('/tmp/world', (err, stats) => {
      if (err) throw err;
      console.log(`stats: ${JSON.stringify(stats)}`);
    });
    

    必须通过在一个操作结果返回后再调用另一个操作来正确排序。

    import { rename, stat } from 'node:fs/promises';
    
    const oldPath = '/tmp/hello';
    const newPath = '/tmp/world';
    
    try {
      await rename(oldPath, newPath);
      const stats = await stat(newPath);
      console.log(`stats: ${JSON.stringify(stats)}`);
    } catch (error) {
      console.error('there was an error:', error.message);
    }
    const { rename, stat } = require('node:fs/promises');
    
    (async function(oldPath, newPath) {
      try {
        await rename(oldPath, newPath);
        const stats = await stat(newPath);
        console.log(`stats: ${JSON.stringify(stats)}`);
      } catch (error) {
        console.error('there was an error:', error.message);
      }
    })('/tmp/hello', '/tmp/world');
    

    或者,在使用回调 API 时,将 fs.stat() 调用移动到 fs.rename() 操作的回调中。

    import { rename, stat } from 'node:fs';
    
    rename('/tmp/hello', '/tmp/world', (err) => {
      if (err) throw err;
      stat('/tmp/world', (err, stats) => {
        if (err) throw err;
        console.log(`stats: ${JSON.stringify(stats)}`);
      });
    });
    const { rename, stat } = require('node:fs/promises');
    
    rename('/tmp/hello', '/tmp/world', (err) => {
      if (err) throw err;
      stat('/tmp/world', (err, stats) => {
        if (err) throw err;
        console.log(`stats: ${JSON.stringify(stats)}`);
      });
    });
    

    文件路径#

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

    字符串路径#

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

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

    import { open } from 'node:fs/promises';
    
    let fd;
    try {
      fd = await open('/open/some/file.txt', 'r');
      // Do something with the file
    } finally {
      await fd?.close();
    }
    

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

    import { open } from 'node:fs/promises';
    
    let fd;
    try {
      fd = await open('file.txt', 'r');
      // Do something with the file
    } finally {
      await fd?.close();
    }
    
    文件 URL 路径#

    对于大多数 node:fs 模块函数,pathfilename 参数可以作为使用 file: 协议的 <URL> 对象传入。

    import { readFileSync } from 'node:fs';
    
    readFileSync(new URL('file:///tmp/hello'));
    

    file: URL 始终是绝对路径。

    平台特定注意事项#

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

    import { readFileSync } from 'node:fs';
    // On Windows :
    
    // - WHATWG file URLs with hostname convert to UNC path
    // file://hostname/p/a/t/h/file => \\hostname\p\a\t\h\file
    readFileSync(new URL('file://hostname/p/a/t/h/file'));
    
    // - WHATWG file URLs with drive letters convert to absolute path
    // file:///C:/tmp/hello => C:\tmp\hello
    readFileSync(new URL('file:///C:/tmp/hello'));
    
    // - WHATWG file URLs without hostname must have a drive letters
    readFileSync(new URL('file:///notdriveletter/p/a/t/h/file'));
    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>,这会导致错误。

    import { readFileSync } from 'node:fs';
    // On other platforms:
    
    // - WHATWG file URLs with hostname are unsupported
    // file://hostname/p/a/t/h/file => throw!
    readFileSync(new URL('file://hostname/p/a/t/h/file'));
    // TypeError [ERR_INVALID_FILE_URL_PATH]: must be absolute
    
    // - WHATWG file URLs convert to absolute path
    // file:///tmp/hello => /tmp/hello
    readFileSync(new URL('file:///tmp/hello'));
    

    包含编码斜杠字符的 file: <URL> 在所有平台上都会导致错误。

    import { readFileSync } from 'node:fs';
    
    // On Windows
    readFileSync(new URL('file:///C:/p/a/t/h/%2F'));
    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 */
    
    // On POSIX
    readFileSync(new URL('file:///p/a/t/h/%2F'));
    readFileSync(new URL('file:///p/a/t/h/%2f'));
    /* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
    / characters */
    

    在 Windows 上,包含编码反斜杠的 file: <URL> 会导致错误。

    import { readFileSync } from 'node:fs';
    
    // On Windows
    readFileSync(new URL('file:///C:/path/%5C'));
    readFileSync(new URL('file:///C:/path/%5c'));
    /* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
    \ or / characters */
    
    Buffer 路径#

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

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

    import { open } from 'node:fs/promises';
    import { Buffer } from 'node:buffer';
    
    let fd;
    try {
      fd = await open(Buffer.from('/open/some/file.txt'), 'r');
      // Do something with the file
    } finally {
      await fd?.close();
    }
    
    Windows 上的驱动器特定工作目录#

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

    文件描述符#

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

    基于回调的 fs.open() 和同步的 fs.openSync() 方法打开一个文件并分配一个新的文件描述符。一旦分配,文件描述符即可用于从文件中读取数据、向文件写入数据或请求文件信息。

    操作系统限制了任何给定时间内可打开的文件描述符数量,因此在操作完成后关闭描述符至关重要。否则将导致内存泄漏,最终导致应用程序崩溃。

    import { open, close, fstat } from 'node:fs';
    
    function closeFd(fd) {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
    
    open('/open/some/file.txt', 'r', (err, fd) => {
      if (err) throw err;
      try {
        fstat(fd, (err, stat) => {
          if (err) {
            closeFd(fd);
            throw err;
          }
    
          // use stat
    
          closeFd(fd);
        });
      } catch (err) {
        closeFd(fd);
        throw err;
      }
    });
    

    基于 Promise 的 API 使用 <FileHandle> 对象代替数值文件描述符。这些对象由系统更好地管理,以确保不会泄露资源。但是,仍然需要在操作完成后关闭它们。

    import { open } from 'node:fs/promises';
    
    let file;
    try {
      file = await open('/open/some/file.txt', 'r');
      const stat = await file.stat();
      // use stat
    } finally {
      await file.close();
    }
    

    线程池使用#

    所有基于回调和 Promise 的文件系统 API(fs.FSWatcher() 除外)都使用 libuv 的线程池。这对某些应用程序可能会产生令人惊讶且负面的性能影响。有关详细信息,请参阅 UV_THREADPOOL_SIZE 文档。

    文件系统标志#

    以下标志在 flag 选项接受字符串的任何地方均可用。

    • 'a':以追加模式打开文件。如果文件不存在则创建它。

    • 'ax':类似于 'a',但如果路径存在则失败。

    • 'a+':以读取和追加模式打开文件。如果文件不存在则创建它。

    • 'ax+':类似于 'a+',但如果路径存在则失败。

    • 'as':以同步模式打开文件以进行追加。如果文件不存在则创建它。

    • 'as+':以同步模式打开文件以进行读取和追加。如果文件不存在则创建它。

    • 'r':以读取模式打开文件。如果文件不存在则抛出异常。

    • 'rs':以同步模式打开文件以进行读取。如果文件不存在则抛出异常。

    • '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_WRITE,或者 O_EXCL|O_CREAT 转换为 CreateFileW 接受的 CREATE_NEW

    排他标志 'x'open(2) 中的 O_EXCL 标志)会导致路径存在时操作返回错误。在 POSIX 上,如果路径是符号链接,即使链接指向不存在的路径,使用 O_EXCL 也会返回错误。排他标志可能在网络文件系统上无法工作。

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

    修改文件而不是替换文件可能需要将 flag 选项设置为 'r+' 而不是默认的 'w'

    某些标志的行为因平台而异。因此,在 macOS 和 Linux 上使用 'a+' 标志打开目录(如下例所示)将返回错误。相反,在 Windows 和 FreeBSD 上,将返回文件描述符或 FileHandle

    // macOS and Linux
    fs.open('<directory>', 'a+', (err, fd) => {
      // => [Error: EISDIR: illegal operation on a directory, open <directory>]
    });
    
    // Windows and FreeBSD
    fs.open('<directory>', 'a+', (err, fd) => {
      // => null, <fd>
    });
    

    在 Windows 上,使用 'w' 标志打开现有的隐藏文件(通过 fs.open()fs.writeFile()fsPromises.open())将失败并报错 EPERM。现有的隐藏文件可以使用 'r+' 标志打开以进行写入。

    调用 fs.ftruncate()filehandle.truncate() 可用于重置文件内容。