公開日: 2011年09月12日(Mon)
node.js 入門の続き。WebSocketをはじめる前に、データの読み書きができないと様々不便だと思ったので、やってみた。
ドキュメントのファイルシステムの節を参考に、ファイルの読み書きをやってみる。
まず最初に、ファイルシステムモジュール 'fs' のインスタンスを作成する。
var fs = require('fs');
この fs
にファイルの読み書きをするための機能が詰め込まれているっぽい。
関数名をざっと眺めると、それぞれ ****Sync()
という関数が対で用意されている(例:fs.readFile()
と fs.readFileSync()
など)。 Sync
が付いていない方が「非同期」の関数で、付いている方が「同期」の関数のようだ。
ドキュメントには、非同期メソッドでは順序の保証はありません
、また、非同期の形式は常に最後の引数として完了コールバックを受け取ります
とある。おそらく、
ということなんじゃないかと思う。
さて、実際に読み書きをしてみたいと思うが、ドキュメントに File I/O は POSIX 標準の関数に対する単純なラッパーとして提供されます
とあるとおり、基本的にできることは他の言語と同じので、全部はやらない。
ファイルの内容を「読み込む」、「上書き」、「追記」をやってみようと思う。
前準備として、ファイルに関する情報の調べ方を調べておく。次のようにして取得できる。
var stat = fs.statSync('./sample.txt');
fs.statSync()
が返した値 stat
を console.log()
してみると、次のような値が格納されている。
{ dev: 2049,
ino: 491851,
mode: 33188,
nlink: 1,
uid: 1000,
gid: 1000,
rdev: 0,
size: 1556,
blksize: 4096,
blocks: 8,
atime: Mon, 12 Sep 2011 05:59:41 GMT,
mtime: Mon, 12 Sep 2011 05:59:40 GMT,
ctime: Mon, 12 Sep 2011 05:59:40 GMT }
例えば size
はファイルサイズを示している。
それから、与えられたパスがファイルであれば、stat.isFile()
が true
を返し、ディレクトリであれば stat.isDirectory()
が true
を返す。扱う対象を確認するのに使える。
Reading files with node.js(RUMINATIONS ON CODE)を参考に組んでみた。参考ソースは、ファイルを1行ずつ読み込む外部モジュールとして設計されているようだが、ここではもっとうんと簡略化した実装をしてみる。
細かいところで幾つか謎はあるけど、一応、テキストファイルの読み込みに成功した。
function fileGetContents( filename ){
var fs = require("fs");
var fileContent = "";
var stat = fs.statSync(filename);
var fd = fs.openSync(filename, "r");
var bytes = fs.readSync(fd, stat.size, 0, "ascii");
fileContent += bytes[0];
fs.closeSync(fd);
return fileContent;
};
console.log( fileGetContents( './sample.txt' ) );
fs.openSync()
でファイルを開いて、fs.readSync()
で内容を読み取り、fs.closeSync()
で閉じる、という手続きを踏んでいる。
fs.openSync()
の第2引数に r
を指定している。r
は読み込み専用モードの意味。
fs.readSync()
の第2引数にバッファーサイズを指定するが、ここでは、読み込むファイルのサイズを調べ(stat.size
)、全量を1回で読み込みきるようにした。実際はこのままだと、巨大なファイルを取り扱う場合に難があるかも知れないが、ひとまずよし。
ちなみにこの実装では、なぜか読み込んだテキストの最後に改行(?)が1つ追加されたような感じになってしまう。この改行が何なのかわからないが、EOFか何かなのだろうか? 正体がわからないので上記のソースではそのままにしているが、バッファサイズを stat.size-1
とすれば、とりあえずそれらしい動きにはなる。参考までに。
・・・と思いきや、これを1発でやってくれる便利なラッパーがあった。
var fs = require("fs");
console.log( fs.readFileSync( './sample.txt' ) );
開く→書き込む→閉じるの手続き。読み込みの時と概ね似た手続きだが、fs.openSync()
の第2引数は w
になった。w
は書き込み専用モード。
fs.readSync()
だったところは fs.writeSync()
にしている。fs.writeSync()
の第2引数に、保存したい文字列を渡す。
function fileSaveContents( filename , str ){
var fs = require("fs");
var fd = fs.openSync(filename, "w");
fs.writeSync(fd, str, 0, "ascii");
fs.closeSync(fd);
return true;
};
console.log( fileSaveContents( './sample.txt' , 'sample text.' ) );
上書き保存にも、1発でいける便利なメソッドが用意されていたので、こっちを使った方がよさそう。
var fs = require("fs");
fs.writeFileSync( './sample.txt' , 'contents' );
開く→書き込む→閉じるの手続き。ほぼ同じ。
追記の場合の fs.openSync()
は、a
モードでオープンする。
function filePutContents( filename , str ){
var fs = require("fs");
var fd = fs.openSync(filename, "a");
fs.writeSync(fd, str, 0, "ascii");
fs.closeSync(fd);
return true;
};
filePutContents( './sample2.txt' , 'sample text.'+"\n" );
追記する際に、最後に改行コード "\n"
を付けてないと、1行がどんどん長くなってしまうので注意。
追記を1発でやってくれる便利なラッパーは・・・一見、ないように見える。
とりあえず、簡易的ではあるけれども、ファイルの読み書きができるようになった。ここまでで、簡単なウェブアプリの開発はできる要素がそろったと思う。
実際に、WebSocketなどを使った複雑なアプリケーションを開発する場合は、読み込みや書き込みのステータス管理などをちゃんとやらないと、処理の順番の問題とか出てくると思う。そしたら、非同期系の処理を上手く使う必要が出てくるのかな、多分。
公開日: 2011年09月12日(Mon)