node.js:stdin的readSync?

pan*_*nzi 51 stdin synchronous node.js

是否可以从node.js中的stdin同步读取?因为我正在用JavaScript编写一个关于JavaScript编译器的脑筋(只是为了好玩).Brainfuck支持需要同步实现的读取操作.

我试过这个:

const fs = require('fs');
var c = fs.readSync(0,1,null,'utf-8');
console.log('character: '+c+' ('+c.charCodeAt(0)+')');
Run Code Online (Sandbox Code Playgroud)

但这只产生这个输出:

fs:189
  var r = binding.read(fd, buffer, offset, length, position);
              ^
Error: EAGAIN, Resource temporarily unavailable
    at Object.readSync (fs:189:19)
    at Object.<anonymous> (/home/.../stdin.js:3:12)
    at Module._compile (module:426:23)
    at Module._loadScriptSync (module:436:8)
    at Module.loadSync (module:306:10)
    at Object.runMain (module:490:22)
    at node.js:254:10
Run Code Online (Sandbox Code Playgroud)

dhr*_*ird 54

你有没有尝试过:

fs=require('fs');
console.log(fs.readFileSync('/dev/stdin').toString());
Run Code Online (Sandbox Code Playgroud)

但是,它会等待读入整个ENTIRE文件,并且不会像scanf或cin那样返回.

  • 这个答案为我节省了一堆重构时间 - 谢谢!它看起来不适用于Windows.但我并不太关心这一点. (5认同)
  • 非常方便,但有2**注意事项**:此解决方案(a)**在Windows上不起作用**(如@JesseHallett所述),以及(b)**表现出交互式stdin输入的非标准行为**:不是逐行处理交互式输入,而是`readFileSync()`调用阻塞,直到收到*all*行(由@dhruvbird的免责声明暗示,但值得明确说明). (4认同)
  • **警告 3** 这似乎只读取可用输入的前 65536 个字符 (3认同)
  • 重新 **Windows 支持**:在 v5+ 中,使用 `0` 而不是 `/dev/stdin` 使该方法也适用于 Windows,但从 v9.11.1 开始,存在 [没有输入或 stdin 时的错误关闭](https://github.com/nodejs/node/issues/19831)。 (3认同)

Mar*_*ope 27

在摆弄了一下之后,我找到了答案:

process.stdin.resume();
var fs = require('fs');
var response = fs.readSync(process.stdin.fd, 100, 0, "utf8");
process.stdin.pause();
Run Code Online (Sandbox Code Playgroud)

response将是一个包含两个索引的数组,第一个是输入控制台的数据,第二个是包含换行符的数据长度.

很容易确定何时console.log(process.stdin)枚举所有属性,包括一个标记的属性fd,当然是第一个参数的名称fs.readSync()

请享用!:d

  • 即使在 v0.7.5-pre 上,它也提供与 STDIN 中的普通 fs.readSync 相同的“错误:未知,未知错误”。它适用于哪个版本的节点和操作系统? (2认同)
  • @rjp - 是的,看起来底层依赖库中有一个文件读取错误......好吧不是一个bug,只是一个没有考虑的警告.我*真的*不是一个强大的c开发人员,但看起来stdin上的`open()`调用如果已经打开就会失败.为了解决这个问题,我认为如果句柄是0或1则需要`dup()`句柄,并且在完成后需要`dup2()`句柄.但话又说回来我可能是错误的:D.我会在github上打开一张票,让一些真正的开发者给你正确答案. (2认同)
  • 这个方法原则上仍然有效*(有限制),但是这个答案中的代码不再像`node.js v0.10.4`一样工作,因为接口已经改变了; 看到我的回答. (2认同)

mkl*_*nt0 21

Marcus Pope的答案的更新版本,自node.js v0.10.4开始起作用:

请注意:

  • 一般情况下,节点的流的接口仍然在磁通(双关语半意)和仍然分类为2 - Unstable作为的node.js v0.10.4.
  • 不同的平台表现略有不同; 我看过OS X 10.8.3并且Windows 7:主要区别在于:同步读取交互式标准输入(通过逐行输入终端)仅适用于Windows 7.

这是更新的代码,以256字节的块从stdin同步读取,直到没有更多的输入可用:

var fs = require('fs');
var BUFSIZE=256;
var buf = new Buffer(BUFSIZE);
var bytesRead;

while (true) { // Loop as long as stdin input is available.
    bytesRead = 0;
    try {
        bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE);
    } 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.
    console.log('Bytes read: %s; content:\n%s', bytesRead, buf.toString(null, 0, bytesRead));
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我在输入很长时能够完整捕获STDIN的唯一方法. (2认同)
  • @Sebastian:退一步:答案中的代码得到了很好的评论,并讨论了对_手头问题_重要的问题。您对意大利面条式代码的担忧是否有价值是问题的_偶然_,这里不是讨论它们的地方:您的评论正在分散未来读者的注意力。我已经删除了我以前的评论,以尽量减少分心。 (2认同)

rjp*_*rjp 19

我不知道什么时候出现,但这是一个有益的一步:http://nodejs.org/api/readline.html

var readline = require('readline');

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

rl.on('line', function (cmd) {
  console.log('You just typed: '+cmd);
});
Run Code Online (Sandbox Code Playgroud)

现在我可以从标准输入读取一次.快乐的时光.

  • 这种技术不同步. (24认同)
  • 尼斯; 只是一个单挑:`readline`模块在`Node.js v0.10.4`中仍被归类为'2 - 不稳定'. (2认同)

Nat*_*ero 14

我找到了一个能够完成你需要的库:https://github.com/anseki/readline-sync

  • 这为什么到目前为止?这是最好的答案!它完成了OP在1行代码中想要的东西! (2认同)

ans*_*hul 7

这是使用“async await”的实现。在下面的代码中,输入是从标准输入中获取的,在接收到数据后,标准输入通过使用 `process.stdin.pause();` 停止等待数据。

process.stdin.setEncoding('utf8');

// This function reads only one line on console synchronously. After pressing `enter` key the console will stop listening for data.
function readlineSync() {
    return new Promise((resolve, reject) => {
        process.stdin.resume();
        process.stdin.on('data', function (data) {
            process.stdin.pause(); // stops after one line reads
            resolve(data);
        });
    });
}

// entry point
async function main() {
    let inputLine1 = await readlineSync();
    console.log('inputLine1 = ', inputLine1);
    let inputLine2 = await readlineSync();
    console.log('inputLine2 = ', inputLine2);
    console.log('bye');
}

main();
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案不是同步的。 (3认同)
  • 请解释您的代码如何以及为什么可以帮助将来遇到类似问题的人 (2认同)

use*_*450 7

以下代码从 stdin 读取同步。读取输入直到出现换行符/回车键。该函数返回输入的字符串,并丢弃换行符 (\n) 和回车符 (\r)。这应该与 Windows、Linux 和 Mac OSX 兼容。添加了对 Buffer.alloc 的条件调用(new Buffer(size) 目前已弃用,但某些旧版本缺少 Buffer.alloc。

function prompt(){
    var fs = require("fs");

    var rtnval = "";

    var buffer = Buffer.alloc ? Buffer.alloc(1) : new Buffer(1);

    for(;;){
        fs.readSync(0, buffer, 0, 1);   //0 is fd for stdin
        if(buffer[0] === 10){   //LF \n   return on line feed
            break;
        }else if(buffer[0] !== 13){     //CR \r   skip carriage return
            rtnval += new String(buffer);
        }
    }

    return rtnval;
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*ght 5

重要提示:我刚收到一个.fd未记录的Node.js参与者的通知,并作为内部调试的一种手段.因此,一个人的代码不应该引用它,并且应该手动打开文件描述符fs.open/openSync.

在Node.js 6中,值得注意的是,由于其不安全的特性,不建议Buffer通过其构造函数创建实例new.应该使用Buffer.alloc:

'use strict';

const fs = require('fs');

// small because I'm only reading a few bytes
const BUFFER_LENGTH = 8;

const stdin = fs.openSync('/dev/stdin', 'rs');
const buffer = Buffer.alloc(BUFFER_LENGTH);

fs.readSync(stdin, buffer, 0, BUFFER_LENGTH);
console.log(buffer.toString());
fs.closeSync(stdin);
Run Code Online (Sandbox Code Playgroud)

此外,只应在必要时打开和关闭文件描述符; 每次想要从stdin读取时都这样做会导致不必要的开销.

  • 重要提示:[`.fd` 当前已记录](https://nodejs.org/api/process.html#process_process_stdin_fd)。 (2认同)

exe*_*ook 5

function read_stdinSync() {
    var b = new Buffer(1024)
    var data = ''

    while (true) {
        var n = fs.readSync(process.stdin.fd, b, 0, b.length)
        if (!n) break
        data += b.toString(null, 0, n)
    }
    return data
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一件宝物。感谢分享。我将在我的开源节点模块中实现。经过一些测试后会回来分享节点模块的链接。谢谢! (2认同)