Node.js 的文件系统 (fs) 模块提供了一个与文件系统交互的接口,其模型参照了标准的 POSIX 函数。该模块是 Node.js 的核心部分,支持在本地文件系统上读取、写入和操作文件和目录。
fs 模块公开了三种不同的文件系统操作 API 风格
所有文件系统操作在每种风格中都有对应的方法,为开发人员提供了代码结构上的灵活性。
来源: lib/fs.js1-1169 lib/internal/fs/promises.js1-150 src/node_file.cc1-200 src/node_dir.cc1-100
Node.js 提供了三种不同的方式来与文件系统交互
来源: lib/fs.js172-508 doc/api/fs.md66-122
每种 API 风格都有其使用模式
FileHandle 类提供了一种面向对象的方式来处理文件描述符。这个抽象主要用于基于 Promise 的 API,但它也构成了 Node.js 中所有文件操作的基础。
来源: lib/internal/fs/promises.js158-420 src/node_file.cc220-665
FileHandle 类代表文件系统中的一个打开的文件。它提供了各种文件操作的方法
read、readv、readFile)write、writev、writeFile)stat)close、sync、datasync、truncate)createReadStream、createWriteStream、readableWebStream)FileHandle 会维护自己的生命周期,如果它们在未显式关闭的情况下被垃圾回收,会发出警告。它们还支持 SymbolAsyncDispose 符号,以便在现代 JavaScript 中与 using await 结构一起使用。
来源: lib/internal/fs/promises.js158-420 src/node_file.cc330-390
目录操作提供了读取目录内容和遍历目录的方法
来源: lib/internal/fs/dir.js35-282 src/node_dir.cc100-245
目录 API 允许使用以下功能遍历目录内容
for await...ofDirent 对象获取文件类型信息close() 方法正确清理资源使用异步迭代的示例
来源: lib/internal/fs/dir.js260-282 test/parallel/test-fs-opendir.js45-66
fs 模块提供了几个类来表示文件元数据
来源: lib/internal/fs/utils.js160-215 lib/internal/fs/utils.js380-543
Stats 和 Dirent 类都提供了确定文件系统条目类型的方法。主要区别在于
Stats 由 stat()、lstat() 和 fstat() 操作返回Dirent 由 Dir.read() 等目录迭代方法返回Stats 包含详细信息,如大小、时间戳、权限Dirent 主要包含名称和类型信息isFile()、isDirectory() 等来源: lib/internal/fs/utils.js380-543 lib/internal/fs/utils.js160-215
Node.js 为高效处理大文件提供了基于流的接口,用于文件 I/O
来源: lib/internal/fs/streams.js162-830
文件流建立在 Node.js 的流抽象之上,以提供高效的文件 I/O
fs.createReadStream()),用于读取文件fs.createWriteStream()),用于写入文件FileHandle 对象FileHandle 实例还提供创建流的便捷方法
来源: lib/internal/fs/promises.js356-377 lib/internal/fs/streams.js162-240
Node.js 提供 Web Streams API 集成,以实现现代流接口
来源: lib/internal/fs/promises.js285-341
FileHandle.readableWebStream() 方法从 WHATWG Web Streams API 创建面向字节的 ReadableStream,从而可以更轻松地与 Web 平台 API 和现代 JavaScript 构造(如 ReadableStream.pipeThrough())集成。
fs 模块使用几个包装类来管理异步操作
来源: src/node_file.cc80-95 lib/fs.js80-95 lib/internal/fs/promises.js447-465
请求封装系统提供:
文件系统操作在主线程之外执行,以避免阻塞
来源: doc/api/fs.md142-148 lib/fs.js80-95
线程池实现的关键特性
在选择不同的 API 样式时,请考虑这些性能影响
| API 样式 | 性能特征 |
|---|---|
| 同步 | 阻塞 JavaScript 执行直到完成,代码最简单,但可能导致应用程序冻结 |
| 回调 | 执行时间和内存的最高性能,但错误处理更复杂 |
| Promise | 现代代码风格,错误处理更好,与回调相比有轻微的开销 |
其他性能考虑因素
来源: lib/internal/fs/promises.js507-596 lib/internal/fs/promises.js472-505
fs 模块抽象了操作系统差异,但仍存在一些特定于平台的行为
来源: lib/internal/fs/utils.js359-377 lib/internal/fs/utils.js537-543
以下是使用基于 Promise 的 API 进行常见文件操作的快速参考
| 操作 | 方法 | 描述 |
|---|---|---|
| 读取文件 | readFile() | 读取整个文件内容 |
| 写入文件 | writeFile() | 将数据写入文件,创建或替换 |
| 检查是否存在 | access() | 检查文件是否存在且可访问 |
| 文件信息 | stat() | 获取文件元数据 |
| 文件操作 | rename()、truncate() | 重命名文件或调整其大小 |
| 文件移除 | unlink() | 删除文件 |
| 目录创建 | mkdir() | 创建目录 |
| 目录读取 | opendir() | 读取目录内容 |
| 目录移除 | rmdir() | 移除目录 |
| 符号链接操作 | symlink()、readlink() | 创建和读取符号链接 |
Node.js 文件系统模块提供了一套全面的 API 来处理文件系统。通过其三种 API 样式(回调、同步和基于 Promise),它为不同的编程模式提供了灵活性,同时保持了功能的一致性。
该实现利用 libuv 的线程池在主线程之外执行 I/O 操作,确保 Node.js 应用程序即使在执行繁重的文件操作时也能保持响应。FileHandle 抽象为文件操作提供了一种面向对象的方法,而流接口则允许高效地处理大文件。
了解 fs 模块的架构和性能特征有助于开发人员就为特定用例选择哪种 API 样式和方法做出明智的决定。