如何在Node.js中将一个可读流同时管道传输到两个可写流?

35

目标是:

  1. 创建一个文件读取流。
  2. 将其传输到gzip (zlib.createGzip())。
  3. 然后将zlib输出的读取流传输到:

    1) HTTP response对象

    2) 可写文件流以保存gzipped输出。

现在我可以继续进行到3.1:

var gzip = zlib.createGzip(),
    sourceFileStream = fs.createReadStream(sourceFilePath),
    targetFileStream = fs.createWriteStream(targetFilePath);

response.setHeader('Content-Encoding', 'gzip');

sourceFileStream.pipe(gzip).pipe(response);

...这个方法运行良好,但我还需要将压缩后的数据保存到文件中,这样我就不需要每次重新压缩,并且能够直接流式传输已经压缩的数据作为响应。

那么在Node中如何同时将一个可读流导入两个可写流?

在Node 0.8.x版本中,sourceFileStream.pipe(gzip).pipe(response).pipe(targetFileStream);是否可行?

3个回答

57

管道链接/拆分不像您在这里尝试的那样工作,将第一个发送到两个不同的后续步骤:

sourceFileStream.pipe(gzip).pipe(response);

但是,您可以将同一可读流导入两个可写流中进行传输,例如:

var fs = require('fs');

var source = fs.createReadStream('source.txt');
var dest1 = fs.createWriteStream('dest1.txt');
var dest2 = fs.createWriteStream('dest2.txt');

source.pipe(dest1);
source.pipe(dest2);

1
管道是可链接的。请查看Zlib文档http://nodejs.org/api/zlib.html。您可以看到`raw.pipe(zlib.createGzip()).pipe(response);`我知道你提供的解决方案,但它并不能解决我的问题,因为在我的情况下,我没有特定的读取流。数据是由zlib在运行时生成的,我需要将其数据传输到两个可写流中。 - esengineer
11
管道是可链接的吗?如果考虑到最后一个pipe()不能在第一个“raw”流上工作,那么就不是了。这不像在jQuery中,您可以将其链接以在同一对象上工作。最后一个pipe(response)只是从gzip而不是raw获取输入。 - doup
截至2018年,我能够链接pipe()调用并获得我期望的数据。这在像AWS Lambda函数这样的东西中特别有用 - 从桶中作为流读取; 管道到zlib gunzip; 管道到可写流,将其保存到另一个桶/键中。 - tsalaroth
这个答案帮助我理解了当管道到fs.createWriteStream时,流会结束,所以在此之后它就不能再被链接了。 - lasec0203

17

我发现zlib返回的是可读流,可以稍后将其传送到多个其他流中。因此,我采取了以下方法来解决上述问题:

var sourceFileStream = fs.createReadStream(sourceFile);
// Even though we could chain like
// sourceFileStream.pipe(zlib.createGzip()).pipe(response);
// we need a stream with a gzipped data to pipe to two
// other streams.
var gzip = sourceFileStream.pipe(zlib.createGzip());

// This will pipe the gzipped data to response object
// and automatically close the response object.
gzip.pipe(response);

// Then I can pipe the gzipped data to a file.
gzip.pipe(fs.createWriteStream(targetFilePath));

8
负投票。这是多余的,完全没有添加任何新信息,实际上还增加了混淆。 - Pooyan Khosravi
2
你不能将可写流导向任何地方:https://github.com/nodejs/readable-stream/blob/master/lib/_stream_writable.js#L193 你需要一个双工流或可读流来实现。 - inf3rno

-1
你可以使用 "readable-stream-clone" 包。
const fs = require("fs");
const ReadableStreamClone = require("readable-stream-clone");

const readStream = fs.createReadStream('text.txt');

const readStream1 = new ReadableStreamClone(readStream);
const readStream2 = new ReadableStreamClone(readStream);

const writeStream1 = fs.createWriteStream('sample1.txt');
const writeStream2 = fs.createWriteStream('sample2.txt');

readStream1.pipe(writeStream1)
readStream2.pipe(writeStream2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接