69

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

我试过这个:

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

但这只会产生这个输出:

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
4

11 回答 11

64

你有没有尝试过:

fs=require('fs');
console.log(fs.readFileSync('/dev/stdin').toString());

但是,它将等待整个文件被读入,并且不会像 scanf 或 cin 那样在 \n 上返回。

于 2011-04-26T18:01:36.560 回答
30

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

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

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

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

享受!:D

于 2012-02-16T20:04:30.790 回答
24

从 node.js v0.10.4 开始工作的 Marcus Pope 答案的更新版本:

请注意:

  • 一般来说,节点的流接口仍在不断变化(双关语是有意的),并且仍被归类2 - Unstablenode.js v0.10.4.
  • 不同平台的行为略有不同;我看过OS X 10.8.3and Windows 7:主要区别是:同步读取交互式标准输入(通过逐行输入终端)仅适用于 Windows 7

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

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));
}
于 2013-04-16T22:13:37.333 回答
20

我不知道什么时候出现,但这是向前迈出的有益一步: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);
});

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

于 2013-01-25T01:11:12.157 回答
16

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

于 2015-05-11T21:26:06.440 回答
7

重要提示:我刚刚收到一位.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);

此外,只应在必要时打开和关闭文件描述符;每次希望从标准输入读取数据时都这样做会导致不必要的开销。

于 2016-06-27T14:42:35.683 回答
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();
于 2018-10-11T09:54:49.160 回答
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
}
于 2016-07-06T10:34:24.583 回答
3

我在节点 0.10.24/linux 上使用了这个解决方法:

var fs = require("fs")
var fd = fs.openSync("/dev/stdin", "rs")
fs.readSync(fd, new Buffer(1), 0, 1)
fs.closeSync(fd)

此代码等待按 ENTER。如果用户在按 ENTER 之前输入它,它会从行中读取一个字符。其他字符将保留在控制台缓冲区中,并在后续调用 readSync 时读取。

于 2014-01-15T08:24:43.480 回答
3

以下代码从标准输入读取同步。读取输入直到换行/回车键。该函数返回一个输入字符串,其中换行符 (\n) 和回车符 (\r) 被丢弃。这应该与 Windows、Linux 和 Mac OSX 兼容。添加了对 Buffer.alloc 的条件调用(新的 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;
}
于 2020-02-13T09:02:08.650 回答
0

我编写这个模块是为了从文件或标准输入中一次读取一行。该模块被命名为line-reader它暴露一个ES6 *Generator function以一次迭代一行。这是来自 readme.md 的代码示例(在 TypeScript 中)。

import { LineReader } from "line-reader"

// FromLine and ToLine are optional arguments
const filePathOrStdin = "path-to-file.txt" || process.stdin
const FromLine: number = 1 // default is 0
const ToLine: number = 5 // default is Infinity
const chunkSizeInBytes = 8 * 1024 // default is 64 * 1024

const list: IterableIterator<string> = LineReader(filePathOrStdin, FromLine, ToLine, chunkSizeInBytes)

// Call list.next to iterate over lines in a file
list.next()

// Iterating using a for..of loop
for (const item of list) {
   console.log(item)
}

除了上述代码,您还可以查看reposrc > tests中的文件夹。

注意:-
line-reader模块不会将所有内容读入内存,而是使用生成器函数来生成异步或同步行。

于 2017-06-08T20:33:44.707 回答