Javascript 合并Node.js流

Javascript 合并Node.js流,javascript,node.js,stream,Javascript,Node.js,Stream,我有一堆文件,我从相应的多个流中读取、处理和合并某些数据到单个流中 有没有比下面更优雅的解决方案(有一个单独的计数器,在所有源流发出end后调用combinedStream.end()): 您只需使用转换流处理文件,然后通过管道传输到直通流 既然您使用的是let,我想您可以使用ES2015 "use strict"; let fs=require('fs'); let filePaths=['./tmp/h.txt','./tmp/s.txt']; let Stream = re

我有一堆文件,我从相应的多个流中读取、处理和合并某些数据到单个流中

有没有比下面更优雅的解决方案(有一个单独的计数器,在所有源流发出
end
后调用
combinedStream.end()
):


您只需使用转换流处理文件,然后通过管道传输到直通流

既然您使用的是
let
,我想您可以使用ES2015

  "use strict";

 let fs=require('fs');
 let filePaths=['./tmp/h.txt','./tmp/s.txt'];


 let Stream = require('stream');

  class StreamProcessor  {

   constructor() {
    this.process_streams = [];
   }

   push (source_stream) { 
   // Create a new Transform Stream
   let transform = new StreamTransformer();
    // Register the finish event and pipe
  transform.processed = transform.wait.call(transform);
   source_stream.pipe(transform);
   // push the stream to the internal array
  this.process_streams.push(transform);
   }

   done (callback) {  
    let streams = this.process_streams;
 // Wait for all Transform streams to finish processing
   Promise.all( 
   streams.map(function(s) {return s.processed; })
   )
   .then ( function() {
   let combined_stream=new Stream.PassThrough();
   streams.forEach(function (stream) {
   stream.pipe(combined_stream); 
   });
   // Call the callback with stream
    callback(null,combined_stream);
   })
   .catch(function (err) {
    callback(err);
    });
   }

   }     

  class StreamTransformer extends Stream.Transform {
     constructor () {
     // call super
     super();
     } 

     _transform(chunk,enc, transformed) {
     // process files here 
     let data=chunk.toString();
      data=data.substring(0,data.length-2);
     this.push(data);
     transformed();
     }

     _flush(flushed) {
     // for additonal at end
     this.push('\n');
     flushed();
     }

    wait() {
    // returns a promise that resolves, when all the data is processed;
    let stream = this;

    return new Promise(function(resolve,reject)  {
   stream.on('finish', function() {
   resolve(true); });
   stream.on('error', function(err) {
   reject(err);
   });
    });

    }

  }

  ///  Now you can do..

  let process_stream = new StreamProcessor(); 

   filePaths.forEach(function (fpath) {
   let fstream = fs.createReadStream(fpath);
   process_stream.push(fstream);
  });

   process_stream.done(  function
    (err,combined_stream) {
 // Consume the combines stream
 combined_stream.pipe(process.stdout);
  });
测试文件包含“hello”和“stream”

     // Outputs is
    // hell
   // stream 

这可以进一步改进…:/

一种更干净的方法可以用于此,尽管它只不过是将计数器隐藏在某个地方,让您处理一个更舒适的基于回调的模型

这样,您的代码将如下所示:

let sharedStream = ...

function onEachFilename(filename, callback) {
    // here you can read from the stream and push the data on the shared one,
    // then invoke the "internal" callback on the end event
}

function onEndAll() {
    // here you can finalize and close the shared stream
}

forEach(filenames, onEachFilename, onEndAll);

请记住,在某个地方,仍然有一个函数负责为您计数,并在调用所有的
回调
函数后调用
onEnd
函数。

当然,通过将所有流输送到组合流,将在后者上多次调用结束事件!!我想对于需要从该流中读取的组件来说,这将是一件棘手的事情…@cswl正如我所说的,我不会将整个文件传输到组合流中。只有文件中的一些数据被写入组合流
myStream.on('data',myStream.write)
,因此我需要知道何时关闭组合流。@cswl谢谢,但它看起来更复杂,不是吗simpler@kyrylkov. 您可以将这些类放在一个单独的文件中,并将其作为模块加载。然后你的整个代码在
//之后变成了
@cswl谢谢。我把它作为另一种解决方案,但不是答案。谢谢。我把它作为替代方案投了赞成票,但不是答案。
let sharedStream = ...

function onEachFilename(filename, callback) {
    // here you can read from the stream and push the data on the shared one,
    // then invoke the "internal" callback on the end event
}

function onEndAll() {
    // here you can finalize and close the shared stream
}

forEach(filenames, onEachFilename, onEndAll);