fs.writeFile(path, data, callback) 把一个字符串或 Buffer 写入文件。文件不存在时,Node 会创建它;文件已存在时,原来的内容会被替换。fs.writeFileSync(path, data) 做的是同样的事,但会等写入完成;fs.appendFile 则是追加到文件末尾,而不是替换。
它先打印 saved,再打印读回来的文本;回调只会收到一个错误(或 null),永远不会收到数据。把字符串换成 42,调用就会抛出 TypeError:数据必须是字符串或 Buffer。
writeFile、writeFileSync 与 fs/promises
三种形式接收相同的参数,区别在于你如何等待结果。
const fs = require('fs');
const fsp = require('fs/promises');
fs.writeFileSync('a.txt', 'one'); // blocks, throws on error
fs.writeFile('b.txt', 'two', (err) => {}); // callback with err
await fsp.writeFile('c.txt', 'three'); // promise, use in async code
在脚本和启动代码中用 writeFileSync,在服务器中用 Promise 版本,因为同步写入会在磁盘完成之前卡住其他所有请求。Promise API 的其余内容见 fs/promises 页面。
用 appendFile 追加到文件
writeFile 会替换整个文件。要往日志里加一行,请用 appendFile,它在第一次调用时也会创建文件。
第一次读取打印 "second\n",因为第二个 writeFileSync 替换掉了 first;第二次打印 "second\nthird\nfourth\n"(JSON.stringify 让换行符显示出来)。换行符 \n 要你自己加:两个函数都不会自动添加。
writeFile | appendFile | |
|---|---|---|
| 文件不存在 | 创建它 | 创建它 |
| 文件已存在 | 替换内容 | 追加到末尾 |
| 默认标志 | 'w' | 'a' |
| 典型用途 | 保存整个文档或 JSON | 日志,每次一行 |
不要覆盖:flag 选项
第三个参数可以是一个选项对象。其中的 flag 决定已存在的文件会怎样。'wx' 的意思是“写入,但如果文件已经存在就失败”,这是只创建一次文件的安全做法。
第二次调用以 EEXIST 失败,所以文件里仍然是 abc123。把第二次调用的文件名改成 id2.txt,两次调用都会打印 created。
最常见的几个标志:'w'(默认,替换)、'a'(追加)、'wx'(只创建)和 'ax'(追加,但只针对新文件)。
先用 fs.existsSync 检查再写入,中间会有一个空档:另一个进程可能在检查和写入之间创建了这个文件。'wx' 一步就完成了这两件事。
把 JSON 写入文件
writeFile 不接受对象。用 JSON.stringify 把对象转成文本;第三个参数 2 会让输出带缩进,文件更易读。
文件中的对象分成了几行并带有缩进,解析回来会得到一个相等的对象,所以最后一行打印 2。不经过 JSON.stringify 直接传入对象,调用会抛出 TypeError。
先用 mkdir 创建文件夹
writeFile 只创建文件,不创建文件夹。reports 不存在时写入 reports/2026/june.txt 会以 ENOENT 失败。先用带 { recursive: true } 的 mkdir 创建路径,它会创建所有缺失的文件夹,文件夹已存在时则什么也不做。
第一次写入以 ENOENT 失败;mkdir 之后,同样的写入成功了,readdir 列出 [ 'june.txt' ]。在真实代码中用 path.join 拼这些路径,这样在 Windows 上也能正常工作。
常见错误
以为调用之后文件就写好了。 fs.writeFile 在数据写入磁盘之前就返回了。在回调里读取文件或开始下一步,或者 await 它的 Promise 版本。
在循环中写入导致数据丢失。 每一项调用一次 writeFile,每次都会替换文件,最后只剩下最后一项。用 appendFile,或者先拼好整个字符串再写一次。
写入了 [object Object]。 把对象传给 String() 或模板字符串,写进去的是 [object Object]。请使用 JSON.stringify。
常见问题
fs.writeFile 会覆盖文件吗?
会。使用默认标志 'w' 时,它会清空文件再写入新数据,原来的内容就没了。要追加到末尾,请传入 { flag: 'a' } 或使用 appendFile。
文件不存在时,fs.writeFile 会创建它吗?
会,它会创建文件。但它不会创建缺失的文件夹:logs 不存在时写入 logs/app.log 会以 ENOENT 失败。
数据可以传什么类型?
字符串、Buffer 或类型化数组。传入其他类型,比如对象或数字,都会抛出 TypeError,所以要先用 JSON.stringify 转换对象,用 String() 转换数字。
可以同时对同一个文件多次调用 writeFile 吗?
不可以。对同一个文件并行调用两次 writeFile,写入可能交错,留下混在一起的内容。等一次写完再开始下一次,或者把数据收集起来只写一次。