2つのストリーム:
読み取り可能 streamsstream1
とstream2
が与えられた場合、stream1
とstream2
を連結したストリームを取得するの慣用的な(簡潔な)方法は何ですか?
stream1.pipe(outStream); stream2.pipe(outStream)
を実行できません。これは、ストリームの内容が混同されるためです。
nストリーム:
EventEmitter が与えられた場合、これは不確定な数のストリームを放出します。
eventEmitter.emit('stream', stream1)
eventEmitter.emit('stream', stream2)
eventEmitter.emit('stream', stream3)
...
eventEmitter.emit('end')
すべてのストリームを連結したストリームを取得するの慣用的な(簡潔な)方法は何ですか?
combined-stream パッケージはストリームを連結します。 READMEの例:
var CombinedStream = require('combined-stream');
var fs = require('fs');
var combinedStream = CombinedStream.create();
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));
combinedStream.pipe(fs.createWriteStream('combined.txt'));
すべてのストリームを一度に追加する必要があると思います。キューが空になると、combinedStream
は自動的に終了します。 問題#5 を参照してください。
stream-stream ライブラリは、明示的な.end
を持つ代替ライブラリですが、あまり人気がなく、おそらく十分にテストされていません。 Node 0.10( この説明 を参照)のstreams2APIを使用します。
これはVanillanodejsで実行できます
import { PassThrough } from 'stream'
const merge = (...streams) => {
let pass = new PassThrough()
let waiting = streams.length
for (let stream of streams) {
pass = stream.pipe(pass, {end: false})
stream.once('end', () => --waiting === 0 && pass.emit('end'))
}
return pass
}
あなたはそれをより簡潔にすることができるかもしれませんが、これがうまくいくものです:
var util = require('util');
var EventEmitter = require('events').EventEmitter;
function ConcatStream(streamStream) {
EventEmitter.call(this);
var isStreaming = false,
streamsEnded = false,
that = this;
var streams = [];
streamStream.on('stream', function(stream){
stream.pause();
streams.Push(stream);
ensureState();
});
streamStream.on('end', function() {
streamsEnded = true;
ensureState();
});
var ensureState = function() {
if(isStreaming) return;
if(streams.length == 0) {
if(streamsEnded)
that.emit('end');
return;
}
isStreaming = true;
streams[0].on('data', onData);
streams[0].on('end', onEnd);
streams[0].resume();
};
var onData = function(data) {
that.emit('data', data);
};
var onEnd = function() {
isStreaming = false;
streams[0].removeAllListeners('data');
streams[0].removeAllListeners('end');
streams.shift();
ensureState();
};
}
util.inherits(ConcatStream, EventEmitter);
状態を追跡するには、streams
(ストリームのキュー; Push
を後ろに、shift
を前に)、isStreaming
、およびstreamsEnded
。新しいストリームを取得したらプッシュし、ストリームが終了するとリスニングを停止してシフトします。ストリームのストリームが終了したら、streamsEnded
を設定します。
これらの各イベントで、現在の状態を確認します。すでにストリーミング(ストリームのパイプ)を行っている場合は、何もしません。キューが空でstreamsEnded
が設定されている場合、end
イベントを発行します。キューに何かがある場合は、再開してそのイベントをリッスンします。
* pause
とresume
は助言であるため、一部のストリームは正しく動作しない可能性があり、バッファリングが必要になることに注意してください。この演習は読者に任されています。
これらすべてを行った後、私はn=2
ケースは、EventEmitter
を作成し、それを使用してConcatStream
を作成し、2つのstream
イベントとそれに続くend
イベントを発行します。もっと簡潔にできると思いますが、手元にあるものを使用したほうがよいでしょう。
https://github.com/joepie91/node-combined-stream2 は、複合ストリームモジュール(上記で説明)のドロップインStreams2互換の代替品です。Streams1ストリームを自動的にラップします。
Combined-stream2のサンプルコード:
var CombinedStream = require('combined-stream2');
var fs = require('fs');
var combinedStream = CombinedStream.create();
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));
combinedStream.pipe(fs.createWriteStream('combined.txt'));
streamee.js は、ノード1.0+ストリームに基づくストリームトランスフォーマーとコンポーザーのセットであり、連結メソッドが含まれています。
var stream1ThenStream2 = streamee.concatenate([stream1, stream2]);
Vanilla nodejsでは、ECMA 15+を使用し、IvoとFengの良い答えを組み合わせています-)。
PassThrough
クラスは些細な Transform
ストリームであり、ストリームを変更することはありません。
const { PassThrough } = require('stream');
const concatStreams = (streamArray, streamCounter = streamArray.length) => streamArray
.reduce((mergedStream, stream) => {
// pipe each stream of the array into the merged stream
// prevent the automated 'end' event from firing
mergedStream = stream.pipe(mergedStream, { end: false });
// rewrite the 'end' event handler
// Every time one of the stream ends, the counter is decremented.
// Once the counter reaches 0, the mergedstream can emit its 'end' event.
stream.once('end', () => --streamCounter === 0 && mergedStream.emit('end'));
return mergedStream;
}, new PassThrough());
このように使用できます:
const mergedStreams = concatStreams([stream1, stream2, stream3]);