node.js:从标准输入读取同步?

发布于 2024-09-13 11:01:59 字数 729 浏览 3 评论 0原文

是否可以从node.js中的stdin同步读取?因为我正在用 JavaScript 编写一个 Brainfuck 的 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

Is it possible to synchronously read from stdin in node.js? Because I'm writing a brainfuck to JavaScript compiler in JavaScript (just for fun). Brainfuck supports a read operation which needs to be implemented synchronously.

I tried this:

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

But this only produces this output:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

哆兒滾 2024-09-20 11:01:59

您是否尝试过:

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

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

Have you tried:

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

However, it will wait for the ENTIRE file to be read in, and won't return on \n like scanf or cin.

一人独醉 2024-09-20 11:01:59

经过一番摆弄后,我找到了答案:

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

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

当您使用 console.log(process.stdin) 枚举所有属性时,很容易确定,其中包括一个标记为 fd 的属性,它当然是第一个参数的名称对于 fs.readSync()

尽情享受吧!
:D

After fiddling with this for a bit, I found the answer:

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

response will be an array with two indexes, the first being the data typed into the console and the second will be the length of the data including the newline character.

It was pretty easy to determine when you console.log(process.stdin) which enumerates all of the properties including one labeled fd which is of course the name of the first parameter for fs.readSync()

Enjoy!
:D

年华零落成诗 2024-09-20 11:01:59

Marcus Pope 答案的更新版本从 node.js v0.10.4 开始运行

请注意:

  • 一般来说,node 的 流接口仍在不断变化(双关语半有意),并且截至 2 - 不稳定代码>node.js v0.10.4。
  • 不同平台的行为略有不同;我研究过 OS X 10.8.3Windows 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));
}

An updated version of Marcus Pope's answer that works as of node.js v0.10.4:

Please note:

  • In general, node's stream interfaces are still in flux (pun half-intended) and are still classified as 2 - Unstable as of node.js v0.10.4.
  • Different platforms behave slightly differently; I've looked at OS X 10.8.3 and Windows 7: the major difference is: synchronously reading interactive stdin input (by typing into the terminal line by line) only works on Windows 7.

Here's the updated code, reading synchronously from stdin in 256-byte chunks until no more input is available:

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));
}
掐死时间 2024-09-20 11:01:59

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

现在我可以从标准输入中一次读取一行。快乐的日子。

I've no idea when this showed up but this is a helpful step forward: 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);
});

Now I can read line-at-a-time from stdin. Happy days.

慕巷 2024-09-20 11:01:59

我找到了一个应该能够满足您需要的库: https://github.com/anseki/readline -同步

I found a library that should be able to accomplish what you need: https://github.com/anseki/readline-sync

染火枫林 2024-09-20 11:01:59

重要提示: Node.js 贡献者刚刚通知我 .fd 未记录,用作内部调试目的的手段。因此,代码不应引用此文件,而应使用 fs.open/openSync 手动打开文件描述符。

在 Node.js 6 中,还值得注意的是,由于其不安全的性质,使用 new 通过其构造函数创建 Buffer 实例已被弃用。人们应该使用 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);

此外,应该只在必要时打开和关闭文件描述符;每次希望从 stdin 读取数据时都执行此操作会导致不必要的开销。

Important: I've just been informed by a Node.js contributor that .fd is undocumented and serves as a means for internal debugging purposes. Therefore, one's code should not reference this, and should manually open the file descriptor with fs.open/openSync.

In Node.js 6, it's also worth noting that creating an instance of Buffer via its constructor with new is deprecated, due to its unsafe nature. One should use Buffer.alloc instead:

'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);

Also, one should only open and close the file descriptor when necessary; doing this every time one wishes to read from stdin results in unnecessary overhead.

请止步禁区 2024-09-20 11:01:59

以下代码从 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;
}

The following code reads sync from stdin. Input is read up until a newline / enter key. The function returns a string of the input with line feeds (\n) and carriage returns (\r) discarded. This should be compatible with Windows, Linux, and Mac OSX. Added conditional call to Buffer.alloc (new Buffer(size) is currently deprecated, but some older versions lack 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;
}
家住魔仙堡 2024-09-20 11:01:59
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
}
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
}
感情废物 2024-09-20 11:01:59

这是“async wait”的实现。在下面的代码中,输入从标准输入获取,接收数据后,标准输入通过使用“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();

Here is the implementation with `async await`. In the below code, the input is taken from standard input and after receiving data the standard input is stopped waiting for data by using `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();
匿名的好友 2024-09-20 11:01:59

我在节点 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 时读取。

I used this workaround on node 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)

This code waits for pressing ENTER. It reads one character from line, if user enters it before pressing ENTER. Other characters will be remained in the console buffer and will be read on subsequent calls to readSync.

迷离° 2024-09-20 11:01:59

我编写了这个 模块 来一次从文件或标准输入中读取一行。该模块被命名为line-reader,它公开了一个ES6 *Generator 函数来一次迭代一行。这是来自 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)
}

除了上面的代码,你还可以看一下 src > repo 中的tests 文件夹。

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

I wrote this module to read one line at a time from file or stdin. The module is named as line-reader which exposes an ES6 *Generator function to iterate over one line at a time. here is a code sample(in TypeScript) from readme.md.

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)
}

Apart from above code, you can also take a look at src > tests folder in the repo.

Note:-
line-reader module doesn't read all stuff into memory instead it uses generator function to generate lines async or sync.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文