Est-il possible de lire de manière synchrone à partir de stdin dans node.js? Parce que j'écris un compilateur brainfuck to JavaScript en JavaScript (juste pour le fun). Brainfuck prend en charge une opération de lecture qui doit être implémentée de manière synchrone.
J'ai essayé ceci:
const fs = require('fs');
var c = fs.readSync(0,1,null,'utf-8');
console.log('character: '+c+' ('+c.charCodeAt(0)+')');
Mais cela ne produit que cette sortie:
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
Je ne sais pas quand cela est arrivé, mais c'est un pas en avant utile: 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);
});
Maintenant, je peux lire ligne à la fois depuis stdin. Jours heureux.
As-tu essayé:
fs=require('fs');
console.log(fs.readFileSync('/dev/stdin').toString());
Cependant, il attendra que le fichier ENTIER soit lu et ne reviendra pas sur\n comme scanf ou cin.
Après avoir manipulé cela un instant, j'ai trouvé la réponse:
process.stdin.resume();
var fs = require('fs');
var response = fs.readSync(process.stdin.fd, 100, 0, "utf8");
process.stdin.pause();
la réponse sera un tableau avec deux index, le premier étant les données saisies dans la console et le second sera la longueur des données, y compris le caractère de nouvelle ligne.
Il était assez facile de déterminer quand vous avez console.log(process.stdin)
qui énumère toutes les propriétés, y compris une propriété nommée fd
qui est bien sûr le nom du premier paramètre de fs.readSync()
Profitez! : D
Une version mise à jour de la réponse de Marcus Pope indiquant que fonctionne à partir de node.js v0.10.4:
Notez s'il vous plaît:
2 - Unstable
à partir de node.js v0.10.4
.OS X 10.8.3
et Windows 7
: la principale différence est la suivante: synchroniquement lecture interactive entrée stdin (en tapant ligne par ligne dans le terminal) ne fonctionne que sous Windows 7.Voici le code mis à jour, qui se lit de manière synchrone à partir de stdin en morceaux de 256 octets jusqu'à ce qu'il n'y ait plus d'entrées disponibles:
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));
}
J'ai trouvé une bibliothèque qui devrait être capable d'accomplir vos tâches: https://github.com/anseki/readline-sync
Important: Un contributeur de Node.js vient de me dire que .fd
est non documenté et sert de moyen de débogage interne . Par conséquent, votre code ne devrait pas faire référence à cela et devrait ouvrir manuellement le descripteur de fichier avec fs.open/openSync
.
Dans Node.js 6, il est également intéressant de noter que la création d'une instance de Buffer
via son constructeur avec new
est déconseillée, en raison de son caractère non sécurisé. On devrait utiliser Buffer.alloc
à la place:
'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);
De plus, il ne faut ouvrir et fermer le descripteur de fichier que lorsque cela est nécessaire; faire cela à chaque fois que l'on souhaite lire à partir de stdin entraîne une surcharge inutile.
J'ai utilisé cette solution de contournement sur le noeud 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)
Ce code attend que vous appuyiez sur ENTER. Il lit un caractère de la ligne, si l'utilisateur le saisit avant d'appuyer sur ENTREE. Les autres caractères resteront dans le tampon de la console et seront lus lors des prochains appels à readSync.
J'ai écrit un petit module complémentaire C++ permettant une lecture synchrone sur le clavier ( https://npmjs.org/package/kbd ).
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
}
process.stdin.setEncoding('utf8');
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);
});
});
}
async function main() {
let inputLine1 = await readlineSync();
console.log('inputLine1 = ', inputLine1);
let inputLine2 = await readlineSync();
console.log('inputLine2 = ', inputLine2);
console.log('bye');
}
main();
J'ai écrit ce module pour lire une ligne à la fois à partir d'un fichier ou stdin. Le module s'appelle line-reader
, ce qui expose un ES6 *Generator function
à parcourir sur une ligne à la fois. Voici un exemple de code (dans 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)
}
Outre le code ci-dessus, vous pouvez également consulter le dossier src > tests
dans le répertoire repo .
Remarque:-
line-reader module ne lit pas tous les éléments en mémoire mais utilise la fonction générateur pour générer des lignes asynchrones ou synchronisées.