关键术语
硬链接
硬链接是文件系统中的一种特殊机制,允许多个文件名指向同一文件的物理数据块 。每个硬链接共享相同的 inode(索引节点, 用于存储文件或目录的元数据, 通过唯一的 inode 编号 标识每个文件系统对象 ) ,即这些文件名本质上是同一文件的不同入口。例如,文件 file.txt 创建硬链接 link.txt 后,两者指向同一数据,修改任一文件内容都会同步到另一个文件。
符号链接
实质
是文件系统中的一种特殊文件(如Linux的l类型文件,Windows的.symlink),其核心功能是通过路径引用指向另一个文件或目录。与快捷方式相似但不是一个东西。
作用
- 符号链接本身不存储实际数据,仅包含目标文件或目录的绝对/相对路径字符串。操作系统会自动将对其的读写操作重定向到目标文件
- 删除符号链接不会影响目标文件;但若目标被删除或移动,符号链接会变为"悬空链接"(Dangling Link),访问时会报错
与硬链接的对比
| 特性 | 符号链接 | 硬链接 |
|---|---|---|
| 存储内容 | 目标路径 | 目标文件的 inode |
| 跨文件系统 | 支持 | 不支持 |
| 目标删除后 | 变为悬空链接 | 仍可访问(文件数据保留) |
| 目录支持 | 支持 | 不支持(仅限文件) |
| 命令示例 | ln -s target link |
ln target link |
作用
进行文件的读写。
使用前提
需要先引用 fs
ini
const fs = require('fs')
文件系统标志
是之后 API 中 flag 参数的值
追加模式(Append Modes)
'a'以追加模式打开文件,文件不存在时自动创建。写入操作始终从文件末尾开始。
示例:日志文件的持续写入'ax'类似'a',但若文件已存在则抛出错误。用于防止意外覆盖现有文件'a+'追加并读取模式。文件不存在时创建,支持同时读写操作,但写入时仍从文件末尾开始'ax+'类似'a+',但文件已存在时抛出错误'as'、'as+'同步模式的追加操作('as'仅追加,'as+'可追加和读取)。文件不存在时创建。
注意:'as' 、 'as+'标志不会使 fs.open() 变为同步阻塞调用,仅改变操作系统层面的 I/O 行为。
读取模式(Read Modes)
- 'r' 只读模式打开文件。若文件不存在则抛出异常。
- 'rs' 同步模式读取文件(绕过系统缓存)。适用于需要强制从磁盘读取最新数据的场景,但会显著降低性能。
- 'r+' 读写模式。文件必须存在,否则抛出异常。
- rs+ 同步读写模式,强制绕过本地文件系统缓存。主要用于NFS挂载文件的访问,避免读取过期的本地缓存数据。
警告:rs+ 模式可绕过本地缓存,适用于网络文件系统(如 NFS)的场景,对I/O性能影响较大,非必要不推荐使用。
写入模式(Write Modes)
'w'写入模式。文件不存在时创建,存在时清空内容(Truncate)'wx'类似'w',但文件已存在时抛出错误。用于确保不会覆盖现有文件'w+'读写模式。文件不存在时创建,存在时清空内容'wx+'与 'w+' 类似,但文件已存在时抛出错误
背诵技巧
只有 w 无 s ,每个标志都有 + 模式,+ 模式表示读写。
x 表示文件存在则抛出错误,但是 r 本身需要文件存在所以无 x
a 文件末尾改写,w 清空改写,二者皆可创建文件
常见错误码:
EBADF:无效文件描述符。ENOSPC:磁盘空间不足。EINTR:写入被信号中断。EEXIST:目录已存在且recursive=false。ENOENT:路径中某部分非目录且recursive=false。EPERM:权限不足(如 Windows 创建根目录)
文件基础操作
fs.open 打开文件
作用
异步打开文件,在文件打开后,可以拿取文件对应的文件描述符,这样就可以通过描述符对文件内容进行操作。
语法
pathstring|Buffer|URL
文件路径,支持字符串、Buffer 或 URL 对象。flagsstring|number
文件系统标志,控制打开方式。默认值:'r'(只读模式)。modestring|integer
设置文件权限(仅当文件被创建时生效),默认值:0o666(可读可写)。callbackFunction
回调函数,接收两个参数:
-
errError:操作错误信息。fdinteger:文件描述符,用于后续操作(如读写)。
fs.close 关闭文件
作用
用于关闭文件描述符,以此来释放资源,防止文件描述符泄露。
语法
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
fd |
integer |
是 | 文件描述符,由 fs.open() 或 fs.openSync()返回 |
callback |
Function |
否 | 操作完成后执行的回调,仅接收可能的错误信息 err。未提供时操作异步执行 |
- 若文件描述符
fd正在被其他异步操作(如并发读取或写入)使用,调用fs.close()会导致未定义行为 - 若是重复关闭则会报错
cookbook
同一文件描述符多次调用 fs.close() 会抛出 EBADF 错误,可通过标志位跟踪关闭状态
常见错误类型:
EBADF: 无效的文件描述符(如已关闭或未打开)。EIO: 底层 I/O 错误(如磁盘故障)
ini
const safeClose = (function () {
let isClosed = false;
return function(fd) {
if (!isClosed) {
fs.close(fd, (err) = {
if (!err) isClosed = true;
});
}
}
})();
fs.fsync 强制刷新缓冲磁盘
作用
将文件描述符 fd 对应的所有数据刷新到存储设备中,确保数据持久化。这样可以使得其他并发打开文件的设备可以观察到文件修改后的内容。
语法
scss
fs.fsync(fd, callback)
- fd integer 已打开的文件描述符。
- callback Function 操作完成后的回调函数,仅接收一个可能的异常参数 err。
cookbook
在文件关闭前,若是对文件内容进行过修改,必须强制刷新下磁盘,确保数据被存储在磁盘中,防止数据丢失。
获取文件元信息
文件元信息 stats 对象的关键属性及方法
- size 文件字节大小
- mtime 最后修改时间(Date 对象)
- birthtime 创建时间(Date 对象)
- mtimeMs 最后修改时间(时间戳)
- birthtimeMs 创建时间(时间戳)
- isFile() 是否为一个文件
isDirectory()是否为目录。- isSymbolicLink() 是否为符号链接
fs.stat 文件、目录元数据
作用
异步获取指定路径资源的元数据信息。
语法
fs.stat(path[, options], callback)
参数
- path 可以为 string 资源路径,Buffer 二进制数据或URL 对象。
- options 配置选项,属性如下:
-
- bigint: boolean ,默认为 false ,表示使用用 BigInt 类型返回元信息中的数字数据。
- callback 在获取到元数据信息后的回调函数
-
- err 获取失败的错误信息【路径不对、权限不足等】
- stats 资源的元数据对象
处理符号链接
fs.stat() 会跟随符号链接获取目标文件的元数据。
那么就代表 stats.isSymbolicLink() 永远返回 flase
若需获取链接本身的元数据,需使用 fs.lstat()
cookbook
- 不推荐在使用 open 或是 readFile 前使用该方法检测文件是否存在,推荐直接进行文件操作并处理错误。单纯检查存在性用 fs.access
fs.promises.stat()
与 fs.stat() 语法类似,但是无回调,相当于 fs.stat() 的 promise 返回值版,promise 返回值为 callback 的第二个参数
fs.lstat()
用法
与 fs.stat 一致,但是在处理符号链接时,会返回符号链接本身的元数据
应用场景:
- 监控符号链接的状态变化(如链接是否被修改)****。
- 检查符号链接的权限是否符合安全要求。
fs.promises.lstat()
与 fs.lstat() 语法类似,但是无回调,相当于 fs.lstat() 的 promise 返回值版,promise 返回值为 callback 的第二个参数
fs.fstat 获取已打开文件元信息
语法
css
fs.fstat(fd[, options], callback)
- fd integer
与 fs.stat 功能语法类似,但是第一个参数为 通过 fs.open() 或 fs.openSync() 方法获取的文件描述符【一个整型数字】。
fs.promises.fstat()
与 fs.fstat() 语法类似,但是无回调,相当于 fs.fstat() 的 promise 返回值版,promise 返回值为 callback 的第二个参数
文件夹增改查
fs.mkdir 创建文件夹
作用
异步方法,用于创建目录并设置目录权限
语法
fs.mkdir(path[, options], callback)
- path string | Buffer | URL
- options Object | integer 是数字则仅仅设置文件夹元数据的 mode 属性,对象则表示配置对象,属性如下:
-
- recursive 若父目录不存在,是否递归创建,默认 flase
- mode string | integer 默认值: 0o777(最高权限,实际受 umask 限制)
- callback 执行命令后的回调函数,参数如下:
-
- err 错误对象
- path 仅在 recursive 为 true 的时候存在,表示首个被创建的目录路径,若是目录已存在且无需新建则为 undefined
fs.promises.mkdir()
与 fs.mkdir() 语法类似,但是无回调,相当于 fs.mkdir() 的 promise 返回值版,promise 返回值为 callback 的第二个参数
写文件
fs.writeFile 创建并写入文件
应用场景
适用于一次性写入较小数据的场景
作用
异步方法,用于将数据完整写入文件。
- 当使用非文件描述符来指定文件时,在不指定操作标记时,操作同 w 。指定了操作标记时则按照操作标记来进行操作
- 该方法是从文件的指针位置开始覆盖文件内容,所以可能会造成文件中部分内容被覆盖的情况。
- 当
file为文件描述符(通过fs.open获取)时,行为类似直接调用fs.write(),但会自动重试直到数据完全写入。
语法
fs.writeFile(file, data[, options], callback)
- file string | Buffer | URL | integer 目标文件路径 或 文件描述符(File Descriptor)。
- data string | Buffer | TypedArray | DataView 要写入的数据,支持字符串、二进制缓冲区等格式。
- options Object | string 若是字符串则 指定 flag 【打开方式 】,若是对象则是配置对象,属性如下:
-
- encoding string | null 编码格式,默认: 'utf8'。若 data 是 Buffer 或二进制类型,此选项被忽略。
- mode integer 文件权限(类 Unix 系统),默认: 0o666(可读可写)。
- flag string 文件操作标志(如 'w' 写入、'a' 追加),默认: 'w'(覆盖写入)。
- flush boolean 写入完成后是否调用 fs.fsync() 强制刷盘,默认: false。启用后(
flush: true),调用fs.fsync()确保数据写入物理磁盘,避免系统缓存丢失。 - signal AbortSignal 允许通过 AbortController 中断写入操作,但无法回滚已写入的数据。
cookbook
- 适用于一次性写入较小数据的场景,每次写入开启 flush 防止内容丢失。
- 大文件写入时,
fs.writeFile会一次性加载所有数据到内存。建议使用流式写入(fs.createWriteStream)分块处理。
fs.promises.writeFile()
与 fs.writeFile() 语法类似,但是无回调,相当于 fs.writeFile() 的 promise 返回值版,promise 返回值为 undefined
fs.write() 写入文件指定内容
作用
异步方法用于像文件内覆盖写入内容
语法
写入二进制数据
普通写法
arduino
fs.write(fd, buffer, offset[, length[, position]], callback)
fdinteger:文件描述符bufferBuffer | TypedArray | DataView :要写入的二进制数据offsetinteger Default:0:buffer 中要写入数据的起始偏移量lengthinteger Default:buffer.byteLength - offset要写入的数据长度positioninteger | null Default:null文件写入位置callbackFunction 写入后的回调函数,参数如下:
-
errErrorbytesWritteninteger 表示从缓冲区实际写入的字节数。bufferBuffer | TypedArray | DataView 源数据,与传入的 buffer 参数是同一个内存空间
选项写法
arduino
fs.write(fd, buffer[, options], callback)
其余的与普通写法一致,但是 options 为一个配置对象,相当于将中间三个可选项集合成一个配置对象:
offsetinteger Default:0lengthinteger Default:buffer.byteLength - offsetpositioninteger Default:null
写入字符串
lua
fs.write(fd, string[, position[, encoding]], callback)
fdinteger:文件描述符stringstring:要写入的字符串positioninteger | null Default:null,表示从文件开头计算的写入位置偏移量。如果类型不是数字,数据将写入当前光标位置encodingstring Default:'utf8'指定字符串编码格式。callbackFunction 写入操作后的回调,参数如下
-
errError:写入错误后的报错writteninteger 已写入字节数stringstring 要写的字符串
cookbook
在没有等待回调的情况下多次调用 fs.write() 操作同一文件是不安全的,原因如下:
- 写入顺序不可控
-
- Node.js 的异步 I/O 机制意味着多次
fs.write()调用可能以不可预测的顺序执行。若未通过回调等待前一次写入完成,可能导致后一次写入覆盖前一次的数据
- Node.js 的异步 I/O 机制意味着多次
- 文件位置(position)冲突
-
fs.write()的position参数需要手动管理。若未显式指定或计算错误,多个异步写入可能定位到同一文件位置,导致数据覆盖(类似 C 语言中非追加模式下的fwrite问题)
- 缓冲区的竞争条件
-
- 底层 I/O 操作通常依赖缓冲区。若多个异步写入同时操作缓冲区,可能因未同步刷新(如未调用类似
fflush()的机制)导致数据未及时落盘,甚至进程崩溃时数据丢失
- 底层 I/O 操作通常依赖缓冲区。若多个异步写入同时操作缓冲区,可能因未同步刷新(如未调用类似
建议使用 fs.createWriteStream()。
fs.createWriteStream()
作用
用于创建可写流,适用于大数据写入和非阻塞 I/O 操作场景。
语法
css
fs.createWriteStream(path[, options])
参数
- path:
string/Buffer/URL,必填,目标文件路径【要写入内容的文件的路径】 - options:
string/Object,默认值 {}, 若为字符串则表示编码格式。
flags
-
-
- 类型:
string - 默认值:
'w'(覆盖写入) - 可选值:
'a'(追加)、'r+'(读写模式)等
- 类型:
-
encoding
-
-
- 类型:
string - 默认值:
'utf8' - 支持编码:
'ascii'、'base64'等,若设为null则返回 Buffer
- 类型:
-
mode
-
-
- 类型:
integer - 默认值:
0o666(可读写权限) - 作用:设置文件权限(如
0o644表示用户可读写,其他只读)
- 类型:
-
start
-
-
- 类型:
integer - 范围:
[0, Number.MAX_SAFE_INTEGER] - 功能:指定写入起始字节位置(如从第 100 字节开始写)
- 类型:
-
autoClose
-
-
- 类型:
boolean - 默认值:
true - 作用:流结束时自动关闭文件描述符,避免内存泄漏
- 类型:
-
highWaterMark
-
-
- 类型:
number - 默认值:
16384(16KB) - 功能:设置内部缓冲区大小,控制背压(Backpressure)【下游处理能力不足时,向上游反馈信号以降低数据生产速率】
- 类型:
-
fd
-
-
- 类型:
integer/FileHandle - 默认值:
null - 说明:若指定文件描述符,则忽略
path参数且不触发'open'事件
- 类型:
-
fs
-
-
- 类型:
Object/null - 默认值:
null - 功能:覆盖底层文件系统实现(需至少重写
write或writev方法)
- 类型:
-
emitClose
-
-
- 作用:用于控制流在销毁时是否触发
'close'事件。 - 默认值:
true(自动触发)
- 作用:用于控制流在销毁时是否触发
-
返回值
一个继承自 stream.Writable 类的 fs.WriteStream 对象。该对象用于以流式方式高效写入文件。
fs.WriteStream 对象
继承
该对象继承自 stream.Writable
Stream | Node.js v23.11.0 Documentation
事件
- close :流关闭且底层文件描述符已释放时触发
- open:文件成功打开后触发,可通过回调参数
fd获取文件描述符 - ready: 在 'open' 事件之后立即触发。 表示流已完成初始化,可以安全调用写入方法
属性及方法
writeStream.bytesWritten: 已写入的字节数- writeStream.path :流写入的文件路径(即 fs.createWriteStream() 的第一个参数)。
若路径是字符串,则此属性为字符串;若路径是 Buffer,则此属性为 Buffer。
- writeStream.pending : 若底层文件尚未打开(在 'ready' 事件触发前),此属性为 true。用于检查流的初始化状态,避免在文件未打开时执行写入操作
- writeStream.close([callback]) : 关闭 writeStream。若提供回调函数,则会在流关闭后执行。
若 autoClose: true(默认),此方法会自动关闭文件描述符并触发 'close' 事件
写入方法的选择
| 指标 | writeFile |
appendFile |
createWriteStream |
write |
|---|---|---|---|---|
| 文件打开次数 | 每次调用 | 每次调用 | 单次打开持续写入 | 需手动管理 |
| 内存占用 | 高 | 高 | 低(分块处理) | 中 |
| 高频写入效率 | 差 | 差 | 优(背压支持) | 优(需优化) |
| 二进制处理能力 | 一般 | 一般 | 优 | 优 |
arduino
是否需精确控制写入位置?
├─ 是 → fs.write + Buffer 操作
└─ 否 → 是否高频?
├─ 是 → createWriteStream
└─ 否 → 是否需要追加内容?
├─ 是 → 数据规模?
│ ├─ 小文件 → appendFile
│ └─ 大文件 → createWriteStream + { flags: 'a' }
└─ 否 → 数据规模?
├─ 小文件 → writeFile
└─ 大文件 → createWriteStream
感觉精细操作用 write ,剩下的无脑用 createWriteStream 就可以
拷贝、剪切文件
fs.rename 剪切文件
作用
异步将文件从 oldPath 重命名或移动到 newPath,在多数文件系统中,重命名操作是原子性的,即要么完全成功,要么完全失败,无中间状态。
- 若
newPath已存在且为文件,则删除源文件。将源文件内容覆盖目标文件内容。 - 若
newPath指向目录(无论是否为空),操作将失败并抛出错误。 - 否则,相当于剪切源文件,粘贴至新位置。
语法
lua
fs.rename(oldPath, newPath, callback)
oldPathstring|Buffer|URL
原文件路径(支持字符串、Buffer 或 URL 对象)。newPathstring|Buffer|URL
新文件路径(若路径指向目录或路径不存在则会抛出错误)。callbackFunction
操作完成后的回调函数,仅接收一个可能的异常参数err。
fs.copyFile拷贝文件
作用
异步将 src 文件复制到 dest。默认情况下,若 dest 已存在则会被覆盖。
语法
css
fs.copyFile(src, dest[, mode], callback)
参数
srcstring|Buffer|URL要复制的源文件路径deststring|Buffer|URL复制操作的目标文件路径modeinteger用于控制复制行为,默认为 0 ,即若dest已存在则会被覆盖。可通过 位或运算 (|) 组合多个常量:
fs.constants.COPYFILE_EXCL
-
-
- 若
dest已存在,则复制操作失败(类似O_EXCL标志)。
- 若
-
fs.constants.COPYFILE_FICLONE可极大提升大文件复制性能。
-
-
- 尝试创建 写时复制(Copy-on-Write)引用链接【延迟复制操作到真正需要修改数据时,从而减少不必要的资源消耗】。若平台不支持写时复制,则回退到普通复制机制。
-
fs.constants.COPYFILE_FICLONE_FORCE
-
-
- 强制尝试创建写时复制引用链接。若平台不支持,则操作直接失败。
-
callbackFunction完成操作后的回调,复制操作可能在中途失败,导致目标文件部分写入(需自行处理残留文件)。
-
errError
文件及文件夹的删除
fs.unlink 删除文件
作用
异步删除文件或符号链接。无法删除目录
- 删除操作实际是减少文件的硬链接计数,当计数归零且无进程打开文件时,存储空间才会释放****。
- 若文件正在被其他进程使用,删除操作仅移除路径入口,数据仍保留至所有进程关闭文件
语法
lua
fs.unlink(path, callback)
- path string | Buffer | URL 要删除的文件或符号链接路径
- callback Function 操作完成时回调
-
- err Error
cookbook
使用时实现删除错误重试
scss
// 删除失败时重试(示例)
function safeUnlink(path, retries = 3) {
fs.unlink(path, (err) = {
if (err && retries 0) {
setTimeout(() = safeUnlink(path, retries - 1), 100);
}
});
}
fs.rmdir 删除文件夹【已废弃,仅兼容旧代码】
作用
异步方法,用于删除目录
语法
fs.rmdir(path[, options], callback)
与 fs.mkdir() 语法类似,但是回调无第二个参数
fs.promises.rmdir()
与 fs.rmdir() 语法类似,但是无回调,相当于 fs.rmdir() 的 promise 返回值版,promise 返回值为 undefined
fs.rm 递归删除文件夹以及文件
语法
css
fs.rm(path[, options], callback)
pathstring|Buffer|URL要删除的文件或目录路径optionsObject可配置选项
-
forceboolean设为true时,若路径不存在则忽略异常。默认值:false。maxRetriesinteger表示错误时最大重试次数,仅在recursive为true时生效。 当遇到EBUSY、EMFILE、ENFILE、ENOTEMPTY或EPERM错误时,Node.js 会以线性退避策略重试操作(每次重试间隔时间递增retryDelay毫秒)。默认值:0。recursiveboolean设为true时,递归删除目录及其内容。失败时会自动重试。默认值:false。retryDelayinteger每次重试的间隔时间(单位:毫秒)。仅在recursive为true时生效。默认值:100。
callbackFunction
-
errError
文件及文件夹的读取
注意事项
读取 base64 格式的图片数据时,读取到的仅仅是图片的数据,不能直接用来展示图片,要展示需要在前面增加 base64 头才可 data:图片MIMEType;base64,
比如一个 jpg 图片 base64 数据为 jkhciquuihdiuhjkwddj2i1h2iuh3iu2hjkhskudiqowudh
那么要使用时,应该用 data:image/jpg;base64,jkhciquuihdiuhjkwddj2i1h2iuh3iu2hjkhskudiqowudh才能展示图片
fs.createReadStream 流读取
作用
以流的形式读取文件内容
语法
css
fs.createReadStream(path[, options])
参数
pathstring|Buffer|URL
文件路径,支持字符串、Buffer 或 URL 对象。optionsstring|Object
可选配置项,可指定编码或文件读取范围等:
-
flagsstring
文件系统标志(如'r'表示只读,'w+'表示读写)。默认值:'r'。encodingstring
指定读取数据的字符编码。默认值:null(返回 Buffer)。fdinteger|FileHandle
已打开的文件描述符或 FileHandle 对象。若指定,将忽略path参数且不触发'open'事件。默认值:null。modeinteger
设置文件模式(权限和 sticky 位),仅在创建文件时生效。默认值:0o666。autoCloseboolean
是否在流关闭时自动关闭文件描述符。默认值:true。emitCloseboolean
是否在流销毁后触发'close'事件。默认值:true。startinteger
读取起始字节位置(包含该字节)。endinteger
读取结束字节位置(包含该字节)。默认值:Infinity。highWaterMarkinteger
控制内部缓冲区的最大字节数。默认值:64 * 1024(64KB)。fsObject|null
可覆盖默认的fs模块方法(如open、read、close)。默认值:null。signalAbortSignal|null
允许中止读取操作。默认值:null。
返回值:fs.ReadStream(可读流对象)
fs.ReadStream
继承
继承自 stream.Readable
Stream | Node.js v23.11.0 Documentation
事件
- close 关闭时触发
- open 当文件描述符打开的时候触发,接收一个参数,该参数为当前流对应文件的文件描述符
- ready 在 open 之后立即触发
属性
- bytesRead :当前已经读取的字节数
- path : 正在读取流的源文件路径,具体值的类型与 createReadStream 的第一个参数有关,可能有三种值:
-
- 若 path 【第一个参数】为字符串,则该属性的值为字符串
- 若为 Buffer 则该属性为 Buffer
- 若为文件描述符,则该属性为 undefined
- pending:表示文件是否尚未打开
fs.readdir 读取文件夹下文件信息
语法
css
fs.readdir(path[, options], callback)
pathstring|Buffer|URL
目标目录的路径。optionsstring|Object
可选配置项,可指定字符编码或高级读取模式:
-
encodingstring
指定返回文件名使用的字符编码,默认值:'utf8'。若设为'buffer',文件名将以Buffer对象形式返回。withFileTypesboolean
设为true时,返回的files数组将包含fs.Dirent对象(而非字符串),用于获取文件类型信息。默认值:false。recursiveboolean
设为true时,递归读取目录内容(包括子目录和嵌套文件)。默认值:false。
callbackFunction
回调函数,接收两个参数:
-
errError操作中可能抛出的错误。filesstring[]|Buffer[]|fs.Dirent[]
目录内文件名数组(不包括.和..)。具体类型由options配置决定。
fs.readFile 读取整个文件内容
语法
css
fs.readFile(path[, options], callback)
pathstring|Buffer|URL|integer
目标文件路径或文件描述符(支持字符串、Buffer、URL 或文件描述符整数)。optionsObject|string
可选配置项,可指定编码、文件标志或中止信号,不指定则返回原始 Buffer:
-
encodingstring|null
指定返回数据的字符编码。默认值:null(返回原始 Buffer)。若设为'utf8'等编码,则返回字符串。flagstring
文件系统标志(如'r'表示只读,'w+'表示读写)。默认值:'r'。signalAbortSignal
允许中止进行中的读取操作(需配合AbortController使用)。
callbackFunction
回调函数,接收两个参数:
-
errError|AggregateError操作中可能抛出的错误。datastring|Buffer文件内容,类型由encoding参数决定。
fs.read 高性能文件读取
语法
arduino
fs.read(fd, buffer, offset, length, position, callback)
fdinteger
通过fs.open打开的文件描述符。bufferBuffer|TypedArray|DataView
数据将被写入的缓冲区。offsetinteger
缓冲区中开始写入数据的偏移量(以字节为单位)。lengthinteger
期望读取的最大字节数。positioninteger|bigint|null
文件读取的起始位置:
-
- 若为
null或-1,从当前文件位置读取,并更新文件位置指针。 - 若为非负整数,从指定位置读取,且文件位置指针保持不变。
- 若为
callbackFunction
回调函数,接收三个参数:
-
errError操作中可能抛出的错误。bytesReadinteger实际读取的字节数(可能小于length)。bufferBuffer被写入数据的缓冲区引用。
css
fs.read(fd[, options], callback)
上面语法的选项版本,options 的属性有 buffer,offset, length, position ,含义与上方一致
arduino
fs.read(fd, buffer[, options], callback)
将 options 中的 buffer 属性放置在第二个参数。
文件内容读取操作cookbook
- 在进行大文件读取或是高并发场景时,使用流式读取(
fs.createReadStream())。 - 高性能场景, 直接使用
fs.read()手动管理读取过程,复用 Buffer 减少中间缓冲开销
文件的监听
应用实例
脚手架中的热更新就是使用 watch 或 fs.watchFile 实现监听文件变更的。
fs.watchFile 低性能高兼容轮询监听单文件
作用
采用轮询检测的方式去检查文件或文件夹状态,若是文件修改则会触发监听事件。
- 当文件不存在时(
ENOENT错误),回调函数会触发一次,所有字段置零(时间戳设为 Unix 纪元)。 - 若文件后续被创建,会再次触发回调,此时
current为最新状态。 - 无法检测重命名
语法
css
fs.watchFile(filename[, options], listener)
无对应的 promise 版本方法
参数:
filenamestring|Buffer|URL
要监视的文件路径。optionsObject
可选配置项:
-
bigintboolean
是否以BigInt格式返回数值(如文件大小、时间戳)。默认值:false。persistentboolean
是否保持进程持续运行(只要监视在运行)。默认值:true。intervalinteger
轮询文件状态的间隔时间(毫秒)。默认值:5007。
listenerFunction
文件状态变化时的回调函数,接收两个参数:
-
currentfs.Stats当前文件状态。previousfs.Stats先前文件状态。
返回值 :fs.StatWatcher 监视器对象,可用于停止监视。
如何关闭监听
使用 fs.unwatchFile
css
fs.unwatchFile(filename[, listener])
参数
filenamestring|Buffer|URL
要停止监视的文件路径。listenerFunction
可选参数,指定要移除的监听器(需与fs.watchFile()绑定的回调函数一致)。
作用
- 若是传入
listener则只会移除listener对应的监听,若是不传,则移除该文件所有监听。 - 若文件
filename未被监视,调用此方法不会报错,也不执行任何操作。
fs.watch 高性能事件驱动递归监听文件
作用
递归监听目录或文件的改变,使用操作系统事件通知,所以更为高效,但是兼容性差
语法
css
fs.watch(filename[, options][, listener])
filenamestring|Buffer|URL
要监视的文件或目录路径。optionsstring|Object
可选配置项(若为字符串,则指定字符编码):
-
persistentboolean
是否保持进程持续运行(只要监视器在运行)。默认值:true。recursiveboolean
是否递归监视子目录(仅部分平台支持目录监视)。默认值:false。encodingstring
指定传递给监听器的文件名编码。默认值:'utf8'。signalAbortSignal
允许通过AbortSignal关闭监视器。
listenerFunction|undefined
事件监听回调函数,接收两个参数:
-
eventTypestring:事件类型('rename'或'change')。filenamestring|Buffer|null:触发事件的文件名(可能为空)。
返回值 :fs.FSWatcher
监视器对象,可监听事件或关闭监视。
参数解析
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
filename |
string/Buffer/URL |
是 | 目标文件或目录路径。 |
options |
string/Object |
否 | 配置项(字符编码或对象)。 |
listener |
Function |
否 | 事件回调函数,接收 eventType和 filename参数。 |
平台实现差异
| 系统 | 底层机制 |
|---|---|
| Linux | 使用 inotify监控文件系统事件。 |
| macOS | 文件使用 kqueue,目录使用 FSEvents。 |
| Windows | 依赖 ReadDirectoryChangesWAPI。 |
| BSD/SunOS | BSD 使用 kqueue,SunOS(含 Solaris 和 SmartOS)使用 event ports。 |
| AIX | 需启用 AHAFS功能。 |
| IBM i | 不支持此功能。 |
- Windows 特有行为
- 监视的目录被移动或重命名时不会触发事件。
- 删除被监视的目录会抛出
EPERM错误。
- listener 中 文件名参数(
filename)
- 支持平台:Linux、macOS、Windows、AIX。
- 可能为空 :即使在这些平台,
filename也可能为null
- Linux/macOS
- 文件删除后重建会分配新 inode,原监视器仅触发删除事件,不跟踪新文件。
- AIX
- 保存并关闭文件会触发两次事件(内容添加和截断)。
如何关闭监听
- 使用 AbortControl 来进行关闭。
ini
const controller = new AbortController();
const watcher = fs.watch('file.txt', { signal: controller.signal });
controller.abort(); // 关闭监视器
watcher.close()关闭
ini
const controller = new AbortController();
const watcher = fs.watch('file.txt', { signal: controller.signal });
watcher.close()
cookbook
- 优先使用 fs.watch ,因为性能好,事件驱动。若是报错则使用 fs.watchFile
- 在监听后使用 unwatchFile 等方法取消监听释放资源。
文件方法的 promise 版
哪些 api 有 promise 版
当前文档中所有的方法都是异步的,除了 fs.watchFile 、fs.unwatchFile,剩下的 都有对应的 promise 版方法。
使用方法
若是不需要传递 fd 参数,那么使用方式为 fs.promise.方法名
否则为 filehandle.方法
参数
参数与普通方法类似,但是有以下不同
- 不需要传递 callback , callback 除了 err 剩余所有参数都会被包成一个对象作为期约成功兑现的结果 ,err 则会作为期约拒绝时的理由。
- 不需要传递 fd ,而是改为使用
filehandle.方法的形式调用方法,返回期约。filehandle 则是通过 promise 版本的 fs.open 方法拿到的期约兑现结果。
返回值
返回一个期约
示例
不需要传递 fd 的
javascript
const fs = require('fs/promises'); // 或者 require('fs').promise
fs.open('./text.txt', 'r').then(async (res) => {
});
需要传递 fd 的
javascript
const { randomFillSync } = require("crypto");
console.log(Buffer)
const fs = require('fs/promises');
const { Buffer: NodeBuffer } = require('buffer');
fs.open('./text.txt', 'r').then(async (res) => {
// res 为 filehandle
const buf = NodeBuffer.allocUnsafe(10);
randomFillSync(buf, 0, 10);
buf.fill(0);
const r = await res.read(buf, 0, 10, 0); // 这里
console.log(r, buf);
});