Node.jsで標準入力を一気に読む

/dev/stdinとかそういうカッコイイの無いのでそういうのに依存しない方法を調べていた。今はprocess.stdin.fdsizeを調べてそのサイズでBufferオブジェクトを作り、fs.readSync()で読み込むのが良いみたいだ。本当なのかな?

#!/usr/bin/env node

var fs = require('fs');

var fd = process.stdin.fd;
var length = fs.fstatSync(fd).size;
var buffer = new Buffer(length);
var bytesRead = fs.readSync(fd, buffer, 0, length, 0);
var input = buffer.toString('utf8', 0, bytesRead);
console.log(input);

fs.readSync()はその第二引数がBufferオブジェクトじゃない場合はレガシーなモードになるので、Bufferオブジェクトを経由しなくて良かったりもする。

#!/usr/bin/env node

var fs = require('fs');

var fd = process.stdin.fd;
var length = fs.fstatSync(fd).size;
var input = fs.readSync(fd, length)[0];
console.log(input);

レガシーなモードでは返り値は[string, bytesRead]という配列になってるので、最初の要素だけを抜き出せば良い。短い。でもv0.8.4のドキュメントではこのことについてもう書かれていないので使わない方が良さそう。

追記

Node.js v5以降ではfs.*File()の第一引数でファイル識別子が利用できるようになった。そのためもはやこのような冗長な記述をする必要はなく、以下のような形で一気に読むことができる。

var fs = require("fs");

var input = fs.readFileSync(process.stdin.fd, "utf8");

標準入力のファイル識別子はprocess.stdin.fdで参照できるので、それを第一引数で指定するだけだ。