【问题标题】:How to pipe one readable stream into two writable streams at once in Node.js?如何在 Node.js 中一次将一个可读流传输到两个可写流?
【发布时间】:2012-12-19 20:33:17
【问题描述】:

目标是:

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

    1) HTTP response 对象

    2) 可写文件流以保存 gzip 后的输出。

现在我可以降到 3.1:

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

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

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

... 效果很好,但我还需要 将 gzip 压缩的数据保存到文件中,这样我就不需要每次都重新压缩并能够直接将 gzip 压缩的数据流式传输为回复。

那么如何在 Node 中将一个可读流同时通过管道传输到两个可写流?

sourceFileStream.pipe(gzip).pipe(response).pipe(targetFileStream); 可以在 Node 0.8.x 中工作吗?

【问题讨论】:

    标签: node.js gzip zlib gzipstream node.js-stream


    【解决方案1】:

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

    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);
    

    【讨论】:

    • 管道可链接的。查看 Zlib 文档 nodejs.org/api/zlib.html。你可以看到raw.pipe(zlib.createGzip()).pipe(response);我知道你给出的解决方案,但它并没有解决我的问题,因为在我的情况下我没有特定的读取流。数据是 zlib 在运行时生成的,我需要将其数据通过管道传输到两个可写流中。
    • 管道是可链式的吗?不,如果您考虑到最后一个 pipe() 不适用于第一个 raw 流。这不像在 jQuery 中你可以链接到同一个对象上。最后一个pipe(response) 只是从gzip 而不是raw 获取输入。
    • 截至 2018 年,我能够链接 pipe() 调用并获得我期望的数据。这在诸如 AWS Lambda 函数之类的东西中特别有用——从存储桶中作为流读取;管道到 zlib gunzip;管道到可写流,将其保存到另一个存储桶/密钥。
    • 这个回答帮助我理解了流在管道到 fs.createWriteStream 时结束,因此在此之后它不能被进一步链接。
    【解决方案2】:

    我发现 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));
    

    【讨论】:

    【解决方案3】:

    你可以使用“可读流克隆”包

    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)
    

    【讨论】:

      猜你喜欢
      • 2014-03-13
      • 2018-06-04
      • 2019-12-01
      • 1970-01-01
      • 2016-06-04
      • 2017-08-27
      • 2021-03-03
      • 1970-01-01
      • 2017-01-15
      相关资源
      最近更新 更多