NIO 之 WatchService
Java 1.6版本以前是不存在目錄監控的API的。如果要實現這種功能必須要自己遍歷目錄,記錄各個文件的情況,然後定時全部遍歷一次,從 JDK7 之後出現了 WatchService
類,實現了對目錄下文件的監控。
整體流程
整個監控目錄文件操作的流程大致如下:
- 獲取 WatchService
- 註冊指定目錄的監視器 WatchService
- 等待目錄下的文件發生變化
- 對發生變化的文件進行操作
獲取 WatchService 實例
WatchService
類的實現實際上是對操作系統的文件監視器的封裝,相比之前的手動實現,優雅了不少。因爲不需要遍歷文件整體而言效率也高很多。以下爲獲取 WatchService
實例的代碼,通過 FileSystem.getDefault() 可看出並非是自己實現的。從 newWatchService()
方法名看, WatchService
可以獲取多個。
WatchService watchService = FileSystems.getDefault().newWatchService();
實際上調用此方法後,程序會新開一個線程,監視文件變化發出的信號,此時線程尚未就緒。
爲目錄註冊監視器
有了監視器,接下來我們需要註冊監視器了。
Path path = Paths.get("src");
WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
註冊監視器需要用到 Path
實例,該實例對應的必須是一個目錄,不允許是一個文件。
方法比較簡單,就是說爲目錄註冊一個監視器,監視目錄下文件的變化。
關於 StandardWatchEventKinds.ENTRY_MODIFY
,表示監視文件的修改事件,它是 WatchEvent.Kind<?>
的實現類。
看起來它像是枚舉,實際上它並不是。JDK 中幫我們定義了三種事件,新增、修改和刪除。
獲取目錄下的變化
獲取目錄的變化需要使用 WatchService
的 take()
方法或 poll()
方法。
WatchKey key = watchService.take();
WatchKey pollKey = watchService.poll();
take()
是一個阻塞方法,會等待監視器發出的信號才返回。poll()
是一個非阻塞方法,會立即返回當時監視器中是否有信號。
返回的 WatchKey
對象,實際上是一個單例,和之前 path.register()
方法返回的實例是同一個。它只能保存某一時間點的文件變化信息。
處理文件變化事件
List<WatchEvent<?>> events = key.pollEvents();
for (WatchEvent<?> pollEvent : events) {
Object o = pollEvent.context();
WatchEvent.Kind kind = pollEvent.kind();
}
key.reset();
pollEvents()
用於獲取文件變化事件,只能獲取一次,不能重複獲取,類似隊列的形式。context()
返回觸發該事件的那個文件或目錄的路徑(相對路徑)kind()
返回事件類型(ENTRY_CREATE、ENTRY_DELETE、ENTRY_MODIFY之一)reset()
每次調用 WatchService 的 take() 或 poll() 方法時需要通過本方法重置。
一個簡單的例子
public void watchServiceExample() throws IOException, InterruptedException {
WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get("D:/code");
WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
// 嘗試獲取下一個變化信息的監控池,如果沒有變化則一直等待
WatchKey key = watchService.take();
for (WatchEvent<?> pollEvent : key.pollEvents()) {
System.out.println(String.format("%s is %s.", pollEvent.context().toString(), pollEvent.kind().name().substring(6)));
}
if (!key.reset()) {
break;
}
}
}
總結
WatchService 的優點就不用多說了,這裏就說一個缺點: 只能監視當前目錄下的文件和目錄,不能監視子目錄 。
參考
[瘋狂Java]NIO.2:WatchService、WatchKey(監控文件變化)
本文如有問題,歡迎在評論區中指正。