如何在node.js中读取整个文本流?

qacovj5a  于 2023-05-06  发布在  Node.js
关注(0)|答案(7)|浏览(121)

在RingoJS中有一个名为read的函数,它允许你读取整个流,直到到达结尾。这在你制作命令行应用程序时很有用。例如,你可以写一个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

这允许您启动一个shell并运行tac命令。然后你输入你想要的行,完成后你可以按Ctrl+D(或Windows上的Ctrl+Z)来发送信号end of transmission
我想在node.js中做同样的事情,但我找不到任何函数可以这样做。我想使用fs库中的readSync函数进行模拟,如下所示,但没有用:

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中同步收集输入文本流中的所有数据并将其作为字符串返回?一个代码示例会很有帮助。

laximzn5

laximzn51#

由于node.js是面向事件和流的,因此没有API等待stdin和buffer结果结束,但很容易手动完成

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解析器)

kiz8lqtg

kiz8lqtg2#

关键是使用这两个Stream事件:

Event: 'data'
Event: 'end'

对于stream.on('data', ...),您应该将数据收集到Buffer(如果是二进制)或字符串中。
对于on('end', ...),您应该使用已完成的buffer调用回调,或者如果您可以内联它并使用Promises库使用return。

xytpbqjk

xytpbqjk3#

让我来举例说明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是一个流。

yjghlzjz

yjghlzjz4#

有一个用于该特定任务的模块,名为**concat-stream**。

cig3rfwq

cig3rfwq5#

如果你在async环境中并且有最新版本的Node.js,这里有一个快速的建议:

const chunks = []
for await (let chunk of readable) {
  chunks.push(chunk)
}
console.log(Buffer.concat(chunks))
ccgok5k5

ccgok5k56#

在Windows上,我在这里发布的其他解决方案中遇到了一些问题-当没有输入时,程序将无限期地运行。
这是现代NodeJS的TypeScript实现,使用异步生成器和for await-比使用旧的基于回调的API更简单,更健壮,这在Windows上工作:

import process from "process";

/**
 * Read everything from standard input and return a string.
 * 
 * (If there is no data available, the Promise is rejected.)
 */
export async function readInput(): Promise<string> {  
  const { stdin } = process;

  const chunks: Uint8Array[] = [];

  if (stdin.isTTY) {
    throw new Error("No input available");
  }

  for await (const chunk of stdin) {
    chunks.push(chunk);
  }

  return Buffer.concat(chunks).toString('utf8');
}

示例:

(async () => {
  const input = await readInput();

  console.log(input);
})();

(如果您想处理Promise拒绝,并在没有输入时显示一个更友好的错误消息,请考虑添加try/catch。)

mum43rcc

mum43rcc7#

这是一个老问题,但值得一提的是,Node.js有一些新的流助手,其中之一是toArray:

require('http')
    .createServer(async (req, res) => {
        const str = (await req.toArray()).toString().toUpperCase();
        res.end(str);
    })
    .listen(4000);

**请注意:**此API目前标记为实验性,因此可能更适合测试/非生产代码。

相关问题