Node.jsのstdinから同期的に読み取ることは可能ですか?なぜなら、私は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
私はこれがいつ現れたのか分かりませんが、これは役に立つ前進です: 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から一度に1行ずつ読み取ることができます。幸せな日々。
やってみました:
fs=require('fs');
console.log(fs.readFileSync('/dev/stdin').toString());
ただし、ファイル全体が読み込まれるまで待機し、scanfやcinのように\ nに戻ることはありません。
これを少しいじった後、私は答えを見つけました:
_process.stdin.resume();
var fs = require('fs');
var response = fs.readSync(process.stdin.fd, 100, 0, "utf8");
process.stdin.pause();
_
応答は2つのインデックスを持つ配列になります。最初のインデックスはコンソールに入力されたデータで、2番目のインデックスは改行文字を含むデータの長さです。
console.log(process.stdin)
の最初のパラメーターの名前であるfd
というラベルが付いたものを含むすべてのプロパティを列挙するfs.readSync()
を決定するのは非常に簡単でした
楽しい! :D
node.js v0.10.4 の時点で機能するMarcus Popeの回答の更新バージョン:
ご注意ください:
2 - Unstable
の時点でnode.js v0.10.4
として分類されています。OS X 10.8.3
とWindows 7
を見てきました:主な違いは次のとおりです: synchronously reading interactive stdin input(by line into the terminal line by line )は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));
}
私はあなたが必要なことを達成できるはずのライブラリを見つけました: https://github.com/anseki/readline-sync
重要: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からの読み取りを希望するたびにこれを行うと、不要なオーバーヘッドが発生します。
ノード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キーを押す前に入力した場合、行から1文字を読み取ります。他の文字はコンソールバッファーに残り、以降のreadSyncの呼び出しで読み取られます。
キーボードで同期読み取りを行う小さなC++アドオンモジュールを作成しました( https://npmjs.org/package/kbd )。
以下に、「async await」を使用した実装を示します。以下のコードでは、入力は標準入力から取得され、データの受信後、標準入力は「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();
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
}
これを書いて module ファイルまたはstdinから一度に1行を読み取ります。モジュールの名前はline-reader
で、ES6 *Generator function
を公開して、一度に1行ずつ繰り返します。これは、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)
}
上記のコードとは別に、 repo のsrc > tests
フォルダーを見ることができます。
注意:-
line-reader モジュールは、すべてのものをメモリに読み込まず、代わりにジェネレーター関数を使用して、行asyncまたはsyncを生成します。