我正在用 Node.js 编写一个程序,(在某些情况下)想要充当一个简单的过滤器:从 stdin 读取所有内容(直到文件末尾),进行一些处理,将结果写入 stdout。
如何执行“从标准输入读取所有内容”部分?到目前为止,我找到的最接近的解决方案似乎要么从控制台一次只适用于一行,要么仅在 stdin 是文件而不是管道时才有效。
我的这个样板很像上面评论中描述的解决方案——在顶层提供它,因为这是最简单的方法,而且不应该只出现在评论中。
var fs = require('fs');
var data = fs.readFileSync(0, 'utf-8');
// data is a string containing the file's contents
我在 Node 11+ 中使用以下内容
async function read(stream) {
const chunks = [];
for await (const chunk of stream) chunks.push(chunk);
return Buffer.concat(chunks).toString('utf8');
}
用途:
const input = await read(process.stdin);
如果您使用的是 Linux,则不需要第 3 方软件包。当然,考虑你的性能需求,但是这两行可以工作:
const fs = require("fs");
const data = fs.readFileSync("/dev/stdin", "utf-8");
Jan 在下面的评论中指出,更便携的解决方案是使用
0
,因为这是 POSIX 标准。所以,你可以简单地使用:
const fs = require("fs");
const data = fs.readFileSync(0, "utf-8");
data
现在是一个包含来自 stdin 的数据的字符串,解释为 utf 8
get-stdin 就可以了。
在问题的字里行间阅读一些注释。
既然您将问题标记为“同步”,我只会注意到 stdin 在 Node.js 中仅是异步的。上面的库是最简单的。它将把整个输入作为字符串或缓冲区处理。
如果可能,以流式传输方式编写程序是最好的,但有些用例对于流式传输是可行的(即字数统计),而有些用例则不可行(即反转输入)。
此外,“控制台一次一行”是终端缓冲您的击键的产物。如果您想要一些“对不起,我问了”级别的详细信息,请查看令人惊叹的TTY Demystified。
除了@Patrick Narkinsky 的解决方案之外,我还没有看到真正同步的解决方案。但是 @Patrick Narkinsky 的答案在 Windows 上不起作用。 似乎是一个 node.js 错误。如果你想了解详细信息,请随意进入这个 github issues 的兔子洞,但我读了一个小时后就放弃了。
我无法在那里找到解决方法(我可能掩盖了它),但是我无意中找到了问题的解决方案。它不漂亮,但很有效。由于该链接仅显示如何记录进度,因此我必须根据自己的需要对其进行修改:
import fs from 'fs';
const BUFSIZE = 256;
const buf = Buffer.alloc(BUFSIZE);
let bytesRead;
let stdin = '';
export function stdinToString(): string {
do {
// Loop as long as stdin input is available.
bytesRead = 0;
try {
bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, null);
} catch (e) {
if (e.code === 'EAGAIN') {
// 'resource temporarily unavailable'
// Happens on OS X 10.8.3 (not Windows 7!), if there's no
// stdin input - typically when invoking a script without any
// input (for interactive stdin input).
// If you were to just continue, you'd create a tight loop.
throw 'ERROR: interactive stdin input not supported.';
} else if (e.code === 'EOF') {
// Happens on Windows 7, but not OS X 10.8.3:
// simply signals the end of *piped* stdin input.
break;
}
throw e; // unexpected exception
}
if (bytesRead === 0) {
// No more stdin input available.
// OS X 10.8.3: regardless of input method, this is how the end
// of input is signaled.
// Windows 7: this is how the end of input is signaled for
// *interactive* stdin input.
break;
}
// Process the chunk read.
stdin += buf.toString(undefined, 0, bytesRead);
} while (bytesRead > 0);
return stdin;
}
我已经编程十多年了,这是第一次
do while
让我的代码更干净:)如果没有它,如果没有标准输入数据存在,这个函数就会挂起——有人可能会说这是代码中的一个错误该链接的。
这回答了最初的问题并且适用于所有操作系统。