node.js流是EventEmitter实例,支持分块处理数据,包含Readable、Writable、Duplex和transform四种类型,适用于大文件读写、网络传输等场景;通过pipe()方法可实现数据高效流转,自动处理背压与错误监听,结合zlib等模块可构建压缩、解析等转换流水线,显著降低内存占用,提升性能。

Node.js 中的流式数据处理是一种高效处理大量数据的方式,特别适用于读取大文件、网络请求响应或实时数据传输等场景。流的核心优势在于它不需要一次性将所有数据加载到内存中,而是以“管道”的方式分块处理,从而节省资源并提升性能。
什么是 node.js 流?
流(stream)是 EventEmitter 的实例,支持按顺序处理数据块。Node.js 提供了四种类型的流:
- Readable:可读流,用于读取数据(如 fs.createReadStream)
- Writable:可写流,用于写入数据(如 fs.createWriteStream)
- Duplex:双工流,既可读又可写(如 TCP 套接字)
- Transform:转换流,在写入和读取时可以修改数据(如 zlib.createGzip)
最常见的应用场景是通过可读流读取文件内容,再通过可写流输出到另一个位置,中间还可以加入转换流进行压缩或解析。
如何使用流进行文件处理?
以下是一个使用流复制大文件的例子,避免内存溢出:
const fs = require(‘fs’);
const readStream = fs.createReadStream(‘large-file.txt’);
const writeStream = fs.createWriteStream(‘copy-file.txt’);
readStream.pipe(writeStream);
pipe() 方法是流处理中最常用的方式,它自动监听 data 事件并把数据写入目标流,语法简洁且不易出错。它等价于手动监听 ‘data’ 和 ‘end’ 事件。
如果需要在传输过程中处理数据,可以插入 Transform 流:
const zlib = require(‘zlib’);
fs.createReadStream(‘large-file.txt’)
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream(‘large-file.txt.gz’));
这段代码实现了边读取边压缩,并输出到一个 .gz 文件,整个过程内存占用很低。
流的错误处理与背压机制
流操作中必须注意错误处理,否则可能导致程序崩溃:
readStream
.on(‘Error’, (err) => console.error(‘读取失败:’, err))
.pipe(writeStream)
.on(‘error’, (err) => console.error(‘写入失败:’, err));
另外,Node.js 流内置了背压(backpressure)机制。当可写流处理速度慢于可读流输出速度时,pipe() 会自动减缓读取节奏,防止内存堆积。这是流比简单事件监听更安全的原因之一。
如果你手动使用 on(‘data’) 处理,就必须关注 writeStream.write() 的返回值。若返回 false,应暂停读取:
readStream.on(‘data’, (chunk) => {
if (!writeStream.write(chunk)) {
readStream.pause();
}
});
writeStream.on(‘drain’, () => {
readStream.resume();
});
实用场景建议
流非常适合以下场景:
- 处理日志文件:逐行读取分析,配合 readline 模块
- 文件上传/下载服务:直接将请求流导入文件或响应
- 数据转换流水线:组合多个 transform 流实现解析、过滤、压缩
- 实时数据推送:如 SSE(Server-Sent Events)响应流
对于小文件,普通 readFile/writeFile 更简单。但对于大文件或高并发服务,流是更稳健的选择。
基本上就这些。掌握流的关键是理解“数据分块流动”的概念,善用 pipe 和内置转换模块,同时别忘了加错误监听。不复杂但容易忽略细节。


