web-dev-qa-db-ja.com

node.jsでテキストストリーム全体を読み取る方法は?

RingoJSには、readと呼ばれる function があり、最後に到達するまでストリーム全体を読み取ることができます。これは、コマンドラインアプリケーションを作成するときに役立ちます。たとえば、次のようにtacprogram と書くことができます。

#!/usr/bin/env ringo

var string = system.stdin.read(); // read the entire input stream
var lines = string.split("\n");   // split the lines

lines.reverse();                  // reverse the lines

var reversed = lines.join("\n");  // join the reversed lines
system.stdout.write(reversed);    // write the reversed lines

これにより、シェルを起動してtacコマンドを実行できます。次に、必要な数の行を入力し、完了したらを押すことができます Ctrl+D (または Ctrl+Z Windowsの場合) 送信の終了 を通知します。

Node.jsで同じことをしたいのですが、そうする関数が見つかりません。 readSyncライブラリのfsfunction を使用して、次のようにシミュレートすることを考えましたが、役に立ちませんでした。

fs.readSync(0, buffer, 0, buffer.length, null);

stdinのファイル記述子 (最初の引数)は0。したがって、キーボードからデータを読み取る必要があります。代わりに、次のエラーが発生します。

Error: ESPIPE, invalid seek
    at Object.fs.readSync (fs.js:381:19)
    at repl:1:4
    at REPLServer.self.eval (repl.js:109:21)
    at rli.on.self.bufferedCmd (repl.js:258:20)
    at REPLServer.self.eval (repl.js:116:5)
    at Interface.<anonymous> (repl.js:248:12)
    at Interface.EventEmitter.emit (events.js:96:17)
    at Interface._onLine (readline.js:200:10)
    at Interface._line (readline.js:518:8)
    at Interface._ttyWrite (readline.js:736:14)

入力テキストストリーム内のすべてのデータを同期的に収集し、node.jsで文字列として返すにはどうすればよいですか?コード例は非常に役立ちます。

22
Aadit M Shah

重要なのは、次の2つのストリームイベントを使用することです。

_Event: 'data'
Event: 'end'
_

stream.on('data', ...)の場合、データデータをバッファ(バイナリの場合)または文字列に収集する必要があります。

on('end', ...)の場合、完了したバッファーを使用してコールバックを呼び出すか、インライン化してPromisesライブラリを使用してreturnを使用できる場合。

14
Nathan

Node.jsはイベントとストリーム指向であるため、stdinとバッファーの結果が終了するまで待機するAPIはありませんが、手動で行うのは簡単です。

var content = '';
process.stdin.resume();
process.stdin.on('data', function(buf) { content += buf.toString(); });
process.stdin.on('end', function() {
    // your code here
    console.log(content.split('').reverse().join(''));
});

ほとんどの場合、データをバッファリングせず、到着時に着信チャンクを処理しない方がよいでしょう(xmlやzlibなどのすでに利用可能なストリームパーサーのチェーンまたは独自のFSMパーサーを使用)

28
Andrey Sidorov

concat-streamと呼ばれるその特定のタスク用のモジュールがあります。

5
Strider

StreetStriderの答えを説明しましょう。

concat-stream でそれを行う方法は次のとおりです

var concat = require('concat-stream');

yourStream.pipe(concat(function(buf){
    // buf is a Node Buffer instance which contains the entire data in stream
    // if your stream sends textual data, use buf.toString() to get entire stream as string
    var streamContent = buf.toString();
    doSomething(streamContent);
}));

// error handling is still on stream
yourStream.on('error',function(err){
   console.error(err);
});

その点に注意してください process.stdinはストリームです。

4
Ali Ok