如何在 node.js 中读取整个文本流?
Posted
技术标签:
【中文标题】如何在 node.js 中读取整个文本流?【英文标题】:How to read an entire text stream in node.js? 【发布时间】:2012-11-04 20:18:24 【问题描述】:在 RingoJS 中有一个名为 read
的 function 允许您读取整个流直到到达末尾。这在您制作命令行应用程序时很有用。例如你可以写一个tac
program如下:
#!/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 (或 Ctrl+Z(在 Windows 上)向end of transmission 发送信号。
我想在 node.js 中做同样的事情,但我找不到任何可以这样做的函数。我想过使用fs
库中的readSync
function来模拟如下,但无济于事:
fs.readSync(0, buffer, 0, buffer.length, null);
file descriptor for 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 中将其作为字符串返回?一个代码示例会很有帮助。
【问题讨论】:
您不能在异步流中同步读取。你为什么要这样做? 我正在尝试做同样的事情。原因是在我的程序中创建一个交互式选项,这有很多原因。异步阅读器并没有太大帮助。 这里是npmjs.com/package/readline-sync: ***.com/questions/8452957/… 【参考方案1】:关键是要使用这两个Stream事件:
Event: 'data'
Event: 'end'
对于stream.on('data', ...)
,您应该将数据数据收集到缓冲区(如果是二进制)或字符串中。
对于on('end', ...)
,您应该使用完成的缓冲区调用回调,或者如果您可以内联它并使用 Promises 库使用 return。
【讨论】:
【参考方案2】:由于 node.js 是面向事件和流的,因此没有 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 解析器)
【讨论】:
你可以在恢复后执行process.stdin.setEncoding('utf-8');
,回调中的bug
已经是字符串了。
类似,但使用Buffer.concat()
: ***.com/questions/10686617/…
@Mitar:这是buf
,而不是bug
。
为什么要反转字符串?
这只是用数据做某事的一个例子【参考方案3】:
有一个用于该特定任务的模块,称为 concat-stream。
【讨论】:
这个模块允许你用另一个字符串散布块。可能只对调试有用:npmjs.org/package/join-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
是一个流。
【讨论】:
【参考方案5】:如果您在 async
上下文中并且拥有最新版本的 Node.js,这里是一个快速的 suggestion:
const chunks = []
for await (let chunk of readable)
chunks.push(chunk)
console.log(Buffer.concat(chunks))
【讨论】:
【参考方案6】:在 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
。)
【讨论】:
以上是关于如何在 node.js 中读取整个文本流?的主要内容,如果未能解决你的问题,请参考以下文章