Node.js Stream 与 Buffer:流式处理入门
Node.js Stream 与 Buffer:流式处理入门
处理一个 2GB 的日志文件,readFile 会把整个文件读进内存——内存直接爆掉。流(Stream)就是为此而生:数据像水流一样一小段一小段地处理。
Buffer:流里的数据块
流中流动的数据是 Buffer——二进制数据的容器,类似数组但固定大小、存的是字节:
const buf = Buffer.from('你好', 'utf8')
console.log(buf.length) // 6(UTF-8 一个汉字 3 字节)
console.log(buf.toString('utf8')) // '你好'
buf[0] // 228,字节的十进制值
四种流
- Readable:可读,如 fs.createReadStream、req
- Writable:可写,如 fs.createWriteStream、res
- Duplex:双向,如 TCP socket
- Transform:读写之间做转换,如 gzip 压缩
import { createReadStream, createWriteStream } from 'node:fs'
import { createGzip } from 'node:zlib'
createReadStream('big.log')
.pipe(createGzip()) // 边读边压缩
.pipe(createWriteStream('big.log.gz')) // 边压缩边写
内存中始终只有一个小块,与文件总大小无关。
背压 backpressure
如果写入速度跟不上读取速度(如慢速网络响应),数据会在内存里堆积。pipe 会自动处理背压——写不动时通知读取端暂停(返回 false),排空后 resume。手写消费时必须检查 write() 的返回值并监听 drain:
readable.on('data', (chunk) => {
if (!writable.write(chunk)) readable.pause() // 写缓冲满了,暂停读
})
writable.on('drain', () => readable.resume()) // 缓冲排空,恢复读
现代写法:异步迭代
Node 15+ 可读流支持 for await...of,比事件写法直观:
async function processFile() {
for await (const chunk of createReadStream('big.log')) {
await process(chunk) // 天然背压:await 期间流会暂停
}
}
典型场景:大文件复制/压缩、日志处理、文件上传转发、HTTP 代理。能流式就不要整进整出。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

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