你的浏览器无法正常显示内容,请更换或升级浏览器!

Node.js 流式处理大文件实战与踩坑

tenfei
tenfei
发布于2026-09-02 14:25 阅读25次
Node.js 流式处理大文件实战与踩坑
分享 Node.js 用流式方式处理大文件的实战经验,涵盖可读流、可写流、管道、背压处理、断点续读、编码陷阱等内容,附代码示例和踩坑记录,避免大文件处理撑爆内存。
# Node.js 流式处理大文件实战与踩坑 > 一次性读取几个 GB 的文件,内存直接爆掉。流式处理是唯一解,但坑也不少。本文分享实战经验和踩过的坑。 ## 一、为什么必须用流 ```js // 错误示范:一次性读入内存 const data = fs.readFileSync("big.log"); // 正确做法:流式逐块处理 const stream = fs.createReadStream("big.log"); ``` readFileSync 会把整个文件加载进内存,几个 GB 的文件直接 OOM。流式是边读边处理,内存占用恒定。 ## 二、核心 API 速览 ### 可读流 + 逐行处理 ```js const readline = require("readline"); const fs = require("fs"); const rl = readline.createInterface({ input: fs.createReadStream("access.log"), crlfDelay: Infinity }); rl.on("line", (line) => { // 逐行处理,内存占用极低 if (line.includes("ERROR")) console.log(line); }); ``` ### 管道传输 ```js const src = fs.createReadStream("input.gz"); const dest = fs.createWriteStream("output.txt"); src.pipe(zlib.createGunzip()).pipe(dest); ``` ## 三、管道与背压 > 注意坑1:忽略背压(Backpressure) ```js // 错误:消费者慢,生产者快,内存越积越多 src.on("data", (chunk) => { slowWrite(chunk); // 写入很慢 }); // 正确:用 pipe 自动处理背压 src.pipe(slowWritable); ``` pipe 内部会处理背压:消费者处理不过来时自动暂停源流。手动监听 data 事件则没有这个保护。 ## 四、常见踩坑 > 坑2:编码问题 ```js // 中文可能乱码,需要显式指定编码 fs.createReadStream("data.txt", { encoding: "utf8" }); ``` > 坑3:流未关闭导致句柄泄漏 ```js // 用完必须关闭,或用 pipeline 自动管理 const { pipeline } = require("stream"); pipeline(src, dest, (err) => { if (err) console.error("管道失败:", err); else console.log("完成"); }); ``` pipeline 会在出错或完成时自动销毁所有流,避免资源泄漏。 > 坑4:分块边界截断 ```js // chunk 大小不固定,可能从汉字中间切断 src.on("data", (chunk) => { console.log(chunk.toString()); // 可能有乱码 }); // 用 StringDecoder 解决 const { StringDecoder } = require("string_decoder"); const decoder = new StringDecoder("utf8"); src.on("data", (chunk) => { console.log(decoder.write(chunk)); }); ``` ## 五、实战:大文件行数统计 ```js const readline = require("readline"); const fs = require("fs"); async function countLines(file) { const rl = readline.createInterface({ input: fs.createReadStream(file), crlfDelay: Infinity }); let count = 0; for await (const line of rl) { count++; } return count; } countLines("huge.log").then((n) => console.log("总行数:", n)); ``` ## 六、内存对比实测 - 一次性读入 2GB 文件:内存峰值约 2GB 以上,极易崩溃 - 流式逐行处理:内存峰值约 30-50MB,稳定运行 结论:处理大文件,务必用流。 ## 七、小结 记住三条原则: 1. 能流式就别整读 2. 能用 pipe/pipeline 就别手动 data 事件 3. 涉及编码转换用 StringDecoder 做到这三点,大文件处理稳如磐石。

2

0

文章点评
Copyright © from 2021 by namoer.com
458815@qq.com QQ:458815
蜀ICP备2022020274号-2