node.js:从标准input读取同步?
是否有可能从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
我不知道什么时候出现,但这是一个有益的步骤: 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); });
现在我可以从标准input一次读取。 快乐的时光。
你有没有尝试过:
fs=require('fs'); console.log(fs.readFileSync('/dev/stdin').toString());
但是,它将等待ENTIRE文件被读入,并且不会像\ scanf或cin \ n那样返回。
在摆弄这个之后,我find了答案:
process.stdin.resume(); var fs = require('fs'); var response = fs.readSync(process.stdin.fd, 100, 0, "utf8"); process.stdin.pause();
响应将是一个有两个索引的数组,第一个是input到控制台的数据,第二个是包含换行符的数据的长度。
确定何时console.log(process.stdin)
枚举所有属性,包括一个标记为fd
的参数fs.readSync()
当然是fs.readSync()
的第一个参数的名称fs.readSync()
请享用! :d
Marcus Pope的答案的更新版本, 作为node.js v0.10.4使用 :
请注意:
- 一般来说, 节点的stream接口仍然处于stream量 (双关半意)状态,仍然被归类为
2 - Unstable
如node.js v0.10.4
。 - 不同的平台行为略有不同; 我已经看过
OS X 10.8.3
和Windows 7
:主要区别在于: 同步阅读交互式 stdininput(通过在terminal行input) 只适用于Windows 7 。
这里是更新后的代码, 从标准input以256字节块同步读取,直到没有更多input可用 :
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
我写了一个小小的C ++附加模块,在键盘上进行同步读取( https://npmjs.org/package/kbd )。
重要信息:我刚刚被Node.js贡献者告知, .fd
没有logging,可作为内部debugging的手段 。 因此,一个人的代码不应该引用这个,并且应该用fs.open/openSync
手动打开fs.open/openSync
。
在Node.js 6中,还值得注意的是,由于其不安全的特性,不build议使用new
构造函数创buildBuffer
的实例。 应该使用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);
另外,必要时只能打开和closures文件描述符; 每当有人希望从标准input读取结果的时候这样做会导致不必要的开销。
我在节点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之前input它。 其他字符将保留在控制台缓冲区中,并将在随后调用readSync时读取。
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 }
我写了这个模块从文件或标准input一次读取一行。 该模块被命名为line-reader
,它公开一个ES6 *Generator function
,一次迭代一行。 这里是来自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
文件夹。
注意:-
线阅读器模块不会读取所有东西到内存中,而是使用生成器函数来生成线asynchronous或同步。