Как читать весь текстовый поток в 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? Пример кода был бы очень полезен.
Ответы
Ответ 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
- это поток.