Node.js 读写文件:fs 模块的三种姿势
Node.js 读写文件:fs 模块的三种姿势
用 Node 写小工具,最先打交道的就是 fs 模块。API 看着一大堆,理清楚其实是三种风格 × 若干操作的矩阵。
三种风格
const fs = require('fs')
const fsp = require('fs').promises
// 1. 回调风格(错误优先)
fs.readFile('./a.txt', 'utf8', (err, data) => {
if (err) throw err
console.log(data)
})
// 2. Promise 风格(推荐)
const data = await fsp.readFile('./a.txt', 'utf8')
// 3. 同步风格
const data2 = fs.readFileSync('./a.txt', 'utf8')
怎么选:
- 日常业务代码用 Promise 版,配合 async/await 最顺手
- 回调版是历史遗留,老代码里常见,知道有 promisify 可以包一层就行
- 同步版只在两种场景用:脚本/CLI 工具(进程就跑一次,阻塞无所谓)、服务启动时读配置(还没开始接请求,必须读完才能继续)。服务运行中千万别用 Sync 版本,会把事件循环整个堵死,所有请求一起卡
路径处理的坑
const path = require('path')
// 错误:相对路径相对于 process.cwd(),即"在哪启动的 node"
fs.readFileSync('./config.json')
// 正确:相对于当前文件所在目录
fs.readFileSync(path.join(__dirname, 'config.json'))
这个坑的特点是本地跑永远没问题——因为你总在项目根目录启动。一上服务器、一换启动目录就炸。铁律:代码里引用资源文件,一律用 __dirname 拼绝对路径;只有用户输入的路径才用相对路径。
路径拼接永远用 path.join(),别手写 '/',Windows 和 Linux 分隔符不一样。
写文件
// 覆盖写(文件不存在则创建)
await fsp.writeFile('./out.txt', 'hello')
// 追加写
await fsp.appendFile('./out.txt', '\nworld')
// 写入前确保目录存在(recursive 一步到位)
await fsp.mkdir('./logs/2019/09', { recursive: true })
writeFile 不会因为目录不存在而帮你建目录,报 ENOENT 了先检查是不是这个问题。
大文件:必须上 Stream
readFile 是把整个文件读进内存。文件几百 MB 时内存直接爆,这时候要用流:
// 流式拷贝,内存占用恒定
fs.createReadStream('./big.log')
.pipe(fs.createWriteStream('./big-copy.log'))
更现代一点的写法,pipeline 自带错误处理和清理:
const { pipeline } = require('stream/promises')
await pipeline(
fs.createReadStream('./big.log'),
fs.createWriteStream('./big-copy.log'),
)
判断标准:文件大小不可控(用户上传、日志)就一律流式;几 KB 的配置文件随便读。
常用操作速查
await fsp.access('./a.txt') // 判断存在(不存在抛异常)
await fsp.stat('./a.txt') // 大小、修改时间、是否目录
await fsp.readdir('./src') // 列目录
await fsp.rename('./a.txt', './b.txt') // 移动/重命名
await fsp.unlink('./a.txt') // 删除文件
await fsp.rm('./dist', { recursive: true, force: true }) // 删目录(force 忽略不存在)
小结
- 默认用
fs.promises,同步版留给脚本和启动阶段 - 路径永远
path.join(__dirname, ...) - 大文件 / 未知大小的文件用 stream + pipeline
- 写文件前先
mkdir({ recursive: true })
fs 模块本身不难,难的是这些"本地测不出来"的坑。把它们提前变成肌肉记忆,写工具脚本就顺畅多了。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~