Node.js: readSync из stdin?

Можно ли синхронно читать из stdin в 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

Ответ 1

Я не знаю, когда это появилось, но это полезный шаг вперед: 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);
});

Теперь я могу читать строки по времени от stdin. Счастливые дни.

Ответ 2

Вы пробовали:

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

Однако он будет ожидать чтения ENTIRE файла и не будет возвращаться на \n, например scanf или cin.

Ответ 3

После того, как я немного поиграл с этим, я нашел ответ:

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

Ответ 4

Обновленная версия Marcus Pope отвечает, что работает как node.js v0.10.4:

Обратите внимание:

  • В общем, node потоковые интерфейсы все еще находятся в движении (наполовину предназначены для ползунков) и являются все еще классифицируется как 2 - Unstable как node.js v0.10.4.
  • Различные платформы ведут себя несколько иначе; Я посмотрел на OS X 10.8.3 и Windows 7: главное отличие: синхронно чтение интерактивного ввода stdin (путем ввода строки по строке) работает только в Windows 7.

Здесь обновленный код , который синхронно считывает из stdin в 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 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));
}

Ответ 5

Я нашел библиотеку, которая должна быть в состоянии выполнить то, что вам нужно: https://github.com/anseki/readline-sync

Ответ 6

Я написал небольшой дополнительный модуль С++, который делает синхронное чтение на клавиатуре (https://npmjs.org/package/kbd).

Ответ 7

Важно: Я только что сообщил вкладчику Node.js, что .fd недокументирован и служит средство для внутренних целей отладки. Поэтому один код не должен ссылаться на это и должен вручную открыть файловый дескриптор с помощью 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);

Кроме того, при необходимости следует открывать и закрывать дескриптор файла; делая это каждый раз, когда вы хотите читать из stdin, вы получаете ненужные накладные расходы.

Ответ 8

Я использовал это обходное решение для 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)

Этот код ждет нажатия ENTER. Он читает один символ из строки, если пользователь вводит его перед нажатием ENTER. Другие символы будут оставлены в консольном буфере и будут прочитаны при последующих вызовах readSync.

Ответ 9

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
}

Ответ 10

Я написал этот модуль для чтения одной строки за раз из файла или stdin. Модуль называется line-reader, который предоставляет ES6 *Generator function итерацию по одной строке за раз. вот пример кода (в TypeScript) из 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)
}

Помимо вышеприведенного кода вы также можете посмотреть папку src > tests в repo.

Примечание: - Страница line-reader модуль не считывает все данные в память, а использует генераторную функцию для генерации строк async или sync.