73 Stimmen

node.js: readSync von stdin?

Ist es möglich, synchron von stdin in node.js zu lesen? Weil ich schreibe ein Brainfuck zu JavaScript-Compiler in JavaScript (nur zum Spaß). Brainfuck unterstützt eine Leseoperation, die synchron implementiert werden muss.

Ich habe dies versucht:

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

Dies führt jedoch nur zu dieser Ausgabe:

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

0 Stimmen

Sparen Sie sich Zeit und verwenden Sie eine gut gepflegte npm-Bibliothek, die das Lesen von stdin abstrahiert, npmjs.com/package/get-stdin .

70voto

dhruvbird Punkte 5716

Haben Sie es schon versucht?

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

Er wartet jedoch darauf, dass die GESAMTE Datei eingelesen wird, und kehrt nicht bei \n wie scanf oder cin.

0 Stimmen

Das reicht nicht aus, denn es muss eine interaktive Eingabeaufforderung sein.

8 Stimmen

Diese Antwort sparte mir eine Menge Zeit bei der Überarbeitung - danke! Es sieht so aus, als würde es unter Windows nicht funktionieren. Aber ich bin nicht zu besorgt darüber.

1 Stimmen

@panzi Wenn Sie wollen, dass es bei jeder Zeile blockiert, müssen Sie einen eigenen C+-Wrapper um getline() oder eine ähnliche Funktion implementieren

30voto

Marcus Pope Punkte 2283

Nachdem ich ein wenig damit herumgespielt hatte, fand ich die Antwort:

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

Die Antwort wird ein Array mit zwei Indizes sein, wobei der erste die in die Konsole eingegebenen Daten und der zweite die Länge der Daten einschließlich des Zeilenumbruchs ist.

Es war ziemlich einfach festzustellen, wann Sie console.log(process.stdin) die alle Eigenschaften auflistet, einschließlich einer Eigenschaft mit der Bezeichnung fd das ist natürlich der Name des ersten Parameters für fs.readSync()

Viel Spaß! :D

2 Stimmen

Sogar auf v0.7.5-pre gibt das den gleichen "Error: UNKNOWN, unbekannter Fehler" wie ein einfacher fs.readSync von STDIN. Auf welcher Version von Node und OS hat das funktioniert?

0 Stimmen

@rjp Ich habe den Code gerade noch einmal überprüft und er hat bei mir unter Windows7 und v0.6.7 funktioniert. Ich bin gerade dabei, 0.6.12 auf meiner Linux-Box einzurichten, also werde ich euch wissen lassen, was ich dort bekomme, wenn es fertig ist

2 Stimmen

@rjp - ja sieht so aus, als gäbe es einen Fehler in den zugrundeliegenden Abhängigkeitslibs für das Lesen von Dateien... nun, kein Fehler, nur ein nicht berücksichtigter Vorbehalt. Ich bin wirklich Ich bin kein starker C-Entwickler, aber es sieht so aus, als ob die open() Aufruf auf stdin schlägt fehl, wenn es bereits geöffnet ist. Um dieses Problem zu umgehen, müssen sie meiner Meinung nach dup() das Handle, wenn das Handle eine 0 oder 1 ist und dup2() den Griff nach Fertigstellung zurück. Aber ich könnte mich ja auch gewaltig irren :D. Ich würde ein Ticket auf Github öffnen und lassen Sie einige echte C-Entwickler geben Ihnen die richtige Antwort.

24voto

mklement0 Punkte 303096

Eine aktualisierte Version der Antwort von Marcus Pope, die funktioniert ab node.js v0.10.4 :

Bitte beachten:

  • Generell, des Knotens Stream-Schnittstellen sind noch im Fluss (Wortspiel halb beabsichtigt) und werden immer noch eingestuft als 2 - Unstable ab dem node.js v0.10.4 .
  • Verschiedene Plattformen verhalten sich leicht unterschiedlich; ich habe mir Folgendes angesehen OS X 10.8.3 y Windows 7 : Der Hauptunterschied ist: synchron Lesen interaktiv stdin-Eingabe (durch zeilenweises Eintippen in den Terminal) funktioniert nur unter Windows 7 .

Hier ist der aktualisierte Code, synchrones Lesen von stdin in 256-Byte-Blöcken, bis kein Input mehr verfügbar ist :

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

2 Stimmen

Dies ist die einzige Möglichkeit, STDIN in seiner Gesamtheit zu erfassen, wenn die Eingabe lang ist.

0 Stimmen

while(true) ? break ? Wenn bytesRead === 0 Ihre Bedingung ist, warum verwenden Sie dann Break-Anweisungen?

0 Stimmen

Ihr Zustand ist nicht true . Ihre Bedingung ist, dass Bytes in stdin vorhanden sind und dass bei der Verarbeitung kein Fehler auftritt. Das ist es, was ich sage. Es ist Spaghetti-Code.

19voto

rjp Punkte 1944

Ich habe keine Ahnung, wann das aufgetaucht ist, aber es ist ein hilfreicher Schritt nach vorn: 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);
});

Jetzt kann ich Zeile für Zeile von stdin lesen. Glückliche Tage.

3 Stimmen

Schön; nur eine Vorwarnung: die readline Modul ist immer noch klassifiziert als 2 - Unstable ab dem Node.js v0.10.4 .

0 Stimmen

@mklement0 Ich glaube, die 2 - Unstable bedeutet, dass die API nicht verbindlich ist und sich noch ändern kann. nodejs.org/api/documentation.html#Dokumentation_Stabilität_index . Ich bin mir nicht sicher, was das in Bezug auf die Stabilität bei der Verwendung bedeutet.

0 Stimmen

@AlainO'Dea: Danke; um die von Ihnen verlinkte Seite zu zitieren: 'Abwärtskompatibilität wird beibehalten, wenn es sinnvoll ist'. Ich lese das als: 'wird sich wahrscheinlich nicht ändern, aber wir behalten uns das Recht vor, dies zu tun', was aus der Sicht eines Benutzers soviel bedeutet wie: 'Die Funktion bleibt erhalten, wahrscheinlich mit der derzeitigen API, aber es besteht eine geringe Chance, dass die API in Zukunft geändert wird'.

16voto

Nate Ferrero Punkte 1378

Ich habe eine Bibliothek gefunden, mit der man das erreichen kann, was man braucht: https://github.com/anseki/readline-sync

2 Stimmen

Warum ist das so weit unten? Das ist die beste Antwort! Es erreicht, was OP will in 1 Zeile Code!

0 Stimmen

Ich fand es nützlich! Ich habe es in ein paar Projekten verwendet und kann bestätigen, dass es tut, was es sagt :)

0 Stimmen

Dies funktioniert nicht bei der Eingabe über die Pipeline. foo | bar donde bar verwendet, versucht readline-sync, vom Terminal zu lesen, nicht von stdin.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X