node.jsでファイル・ディレクトリの監視

使いそうなので調べてみました。
File Systemのfs.watchを使います。

fs.watch('somedir', function (event, filename) {
  console.log('event is: ' + event);
  if (filename) {
    console.log('filename provided: ' + filename);
  } else {
    console.log('filename not provided');
  }
});

非常に簡単に監視ができて良いのですが、使い勝手があまり良くないです。
というのは、ドキュメントに書いてありますが、event'rename''change'のどちらかしか無いです。

  • touchで作成したら'rename'
  • touchで更新したら'change'
  • mvでリネームしたら'rename'でfilenameはリネーム後のファイル名
  • rmで削除したら'rename'
  • chmodで変更したら'rename'

対象のファイルの操作を限定すれば良いかもですが、もう少しイベントが無いと、自由な操作には向かないかもです。

あと、watch()させた後、所定の動作で停止させるにはどうしたら良いのか、調べてみました。

var fs = require('fs')
	dir = './target';

var watcher = fs.watch(dir, {}, function(event, filename) {
	console.log('event is: ' + event);
	if (filename) {
		console.log('filename provided: ' + filename);
	} else {
		console.log('filename not provided');
	}
	if (event === 'rename' && filename === 'stop') {
		console.log('stop');
		watcher.close();
		process.kill(process.pid, 'SIGHUP');
		process.exit(0);
	}
});

fs.watch()の引数を保持しておいて、watcher.close()で監視を止めます。上ではstopというファイルを作成したら、というのを想定しています(renameイベントは多いので、ちゃんとハンドリングする必要はあります)。
ただし、このままだと、イベントループというかプロセスが終了しないので、process.kill()で終了させます。
実際には子プロセス作って監視させたり、停止させるのが良いのかも知れません。
fs.watchFile()はもう少し便利なんだけど、

Stability: 2 - Unstable.  Use fs.watch instead, if possible.

という事で。

[追記]
chokidar / A neat wrapper around node.js fs.watch / fs.watchFile.
というのがあって、便利そうなんだけど、内部でfs.watchFileを使ってるんだよね。