← 返回文章列表
Node.js·492 次阅读

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 条

还没有评论,来抢沙发~

发表评论

评论需审核后显示

© 2026 许冬博客 · 专注 JS 技术分享

·RSS 订阅·Powered by Nuxt 4