Подтвердить что ты не робот

Как читать весь текстовый поток в node.js?

В RingoJS есть функция под названием read, которая позволяет вам читать весь поток до тех пор, пока конец достигнут. Это полезно, если вы создаете приложение командной строки. Например, вы можете написать tac программа следующим образом:

#!/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 функция из fs библиотека для имитации следующим образом, но безрезультатно:

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? Пример кода был бы очень полезен.

4b9b3361

Ответ 1

Ключ должен использовать эти два события Stream:

Event: 'data'
Event: 'end'

Для stream.on('data', ...) вы должны собирать данные данных в буфер (если он является двоичным) или в строку.

Для on('end', ...) вы должны вызвать обратный вызов с завершенным буфером, или если вы можете встроить его и использовать возврат с помощью библиотеки Promises.

Ответ 2

Поскольку node.js является ориентированным на события и потоки, нет API для ожидания до конца результата stdin и буфера, но это легко сделать вручную

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)

Ответ 3

Существует модуль для этой конкретной задачи, называемый concat-stream.

Ответ 4

Позвольте мне проиллюстрировать ответ 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 - это поток.