- WatchService では、指定ディレクトリの監視が可能
サブディレクトリを含めて監視するには、再帰的に監視ディレクトリを WatchService に登録する必要がある
Windows では、WatchService に登録したディレクトリはロックされ、ディレクトリ名のリネームなどが行えない
- Windows では、ReadDirectoryChangesW 関数が使われており、
bWatchSubtreeパラメータが指定できるTRUEの場合、指定されたディレクトリにルート化されたディレクトリ ツリーを監視する
ExtendedWatchEventModifier.FILE_TREEを指定することで、Windows に限り、サブディレクトリを WatchService に登録することなく、サブディレクトリを含めた監視が行える
実装例は以下
import java.nio.file.*; import com.sun.nio.file.ExtendedWatchEventModifier; import static java.lang.IO.println; void main() throws Exception { Path watchPath = Path.of("."); try (WatchService watchService = FileSystems.getDefault().newWatchService()) { WatchEvent.Kind<?>[] kinds = new WatchEvent.Kind<?>[] { StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY }; WatchEvent.Modifier[] modifiers = new WatchEvent.Modifier[] { // windows only ExtendedWatchEventModifier.FILE_TREE }; watchPath.register(watchService, kinds, modifiers); println("watchPath : " + watchPath); for (;;) { WatchKey watchKey = watchService.take(); Path dir = (Path) watchKey.watchable(); for (WatchEvent<?> event : watchKey.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); if (kind == StandardWatchEventKinds.OVERFLOW) { println("OVERFLOW"); continue; } Path path = dir.resolve((Path) event.context()); if (kind == StandardWatchEventKinds.ENTRY_CREATE) { println("CREATE : " + path); } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { println("DELETE : " + path); } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { println("MODIFY : " + path); } else { println("unknown kind: " + kind); } } boolean valid = watchKey.reset(); if (!valid) { break; } } } }
FileSystems..newWatchService()でWatchServiceを取得Path.register()でWatchServiceに自身を監視対象として登録- 監視イベント
StandardWatchEventKindsを指定 - Windows の場合は
xtendedWatchEventModifier.FILE_TREEでサブツリーを対象に指定
- 監視イベント
watchService.take()でWatchKeyを取得- このメソッドはファイル・システムの変更までブロックする
watchKey.pollEvents()で監視対象ディレクトリに発生したイベントを取得する- ファイル・システムの変更が多く、処理が間に合わなかった(内部的に保持しているイベントキューの溢れ)場合は
OVERFLOWイベントが含まれる(WatchEvent.Kind<Object>) OVERFLOWイベント以外は、監視対象として登録したイベントで、event.context()によりパスが取得できるtake()で取得したWatchKeyは、reset()することで、再び監視対象となるreset()の結果がvalidではない場合は、対象ディレクトリが消されたなどで無効となっている