nodo.js: readSync desde stdin?


Es posible leer sincrónicamente desde stdin en el nodo.js? Porque estoy escribiendo un compilador de brainfuck para JavaScript en JavaScript (solo por diversión). Brainfuck admite una operación de lectura que debe implementarse de forma sincrónica.

He intentado esto:

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

Pero esto solo produce esta salida:

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
Author: panzi, 2010-08-07

10 answers

No tengo ni idea de cuándo apareció esto, pero este es un paso adelante útil: 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);
});

Ahora puedo leer línea a línea desde stdin. Días felices.

 20
Author: rjp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-25 01:11:12

¿has probado:

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

Sin embargo, esperará a que se lea TODO el archivo, y no volverá en \n como scanf o cin.

 46
Author: dhruvbird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-26 18:01:36

Después de jugar un poco con esto, encontré la respuesta:

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

La respuesta será una matriz con dos índices, el primero serán los datos introducidos en la consola y el segundo será la longitud de los datos incluyendo el carácter de nueva línea.

Fue bastante fácil determinar cuando console.log(process.stdin) que enumera todas las propiedades, incluyendo una etiqueta fd que es, por supuesto, el nombre del primer parámetro fs.readSync()

Disfrute! : D

 26
Author: Marcus Pope,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-16 20:15:33

Una versión actualizada de la respuesta de Marcus Pope que funciona como de nodo.js v0.10.4:

Tenga en cuenta:

  • En general, las interfaces de flujo del nodo todavía están en flujo (juego de palabras a medias) y todavía se clasifican como 2 - Unstable a partir de node.js v0.10.4.
  • Diferentes plataformas se comportan ligeramente diferente; He mirado OS X 10.8.3 y Windows 7: la principal diferencia es: sincrónicamente leyendo interactivo entrada stdin (escribiendo en la línea terminal por línea) solo funciona en Windows 7.

Aquí está el código actualizado, leyendo sincrónicamente desde stdin en trozos de 256 bytes hasta que no haya más entrada disponible :

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));
}
 20
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-25 19:13:01

Encontré una biblioteca que debería ser capaz de lograr lo que necesitas: https://github.com/anseki/readline-sync

 13
Author: Nate Ferrero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-11 21:26:06

Importante: Acabo de ser informado por un nodo.js colaborador que .fd es indocumentado y sirve como un medio para propósitos de depuración interna . Por lo tanto, el código de uno no debe hacer referencia a esto, y debe abrir manualmente el descriptor de archivo con fs.open/openSync.

En el nodo.js 6, también vale la pena señalar que crear una instancia de Buffer a través de su constructor con new está en desuso, debido a su naturaleza insegura. Uno debe usar Buffer.alloc en su lugar:

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

También, uno debe solo abra y cierre el descriptor de archivo cuando sea necesario; hacer esto cada vez que se desee leer desde stdin resulta en una sobrecarga innecesaria.

 4
Author: James Wright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-27 14:42:35

Escribí un pequeño módulo adicional de C++ que hace que la lectura sincrónica en el teclado ( https://npmjs.org/package/kbd).

 3
Author: user3085414,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-10 04:35:48

Usé esta solución en el nodo 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)

Este código espera para presionar ENTER. Lee un carácter de la línea, si el usuario lo introduce antes de presionar ENTER. Otros caracteres permanecerán en el búfer de la consola y se leerán en llamadas posteriores a readSync.

 3
Author: vadzim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-11 11:12:49
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
}
 2
Author: exebook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-06 10:34:24

Escribí este módulo para leer una línea a la vez desde file o stdin. El módulo se nombra como line-reader que expone un ES6 *Generator function para iterar sobre una línea a la vez. aquí hay un ejemplo de código (en TypeScript) de 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)
}

Aparte del código anterior, también puede echar un vistazo a la carpeta src > tests en el repositorio .

Nota:-
el módulo line-reader no lee todas las cosas en la memoria, sino que usa la función generator para generar líneas async o sync.

 0
Author: Vikas Gautam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-08 20:33:44