Java目錄事件
當文件系統中的對象被修改時,我們可以監聽watch服務以獲取警報。java.nio.file包中的以下類和接口提供watch服務。
- Watchable接口
- WatchService接口
- WatchKey接口
- WatchEvent接口
- WatchEvent.Kind接口
- StandardWatchEventKinds類
Watchable對象表示可以被監視的文件系統對象。Watchable對象可以向watch服務註冊。Path對象是一個Watchable對象。
WatchService表示觀察服務。當一個對象使用WatchService註冊時,WatchService返回一個WatchKey作爲註冊的令牌。WatchEvent表示註冊到監視服務的對象上的事件。 它的kind()方法返回發生的事件的類型。
它的context()方法返回一個Path對象,它表示事件發生的條目。count()方法返回特定通知的事件發生次數。 如果它返回的值大於1,那麼它是一個重複的事件。
WatchEvent.Kind <T>表示發生的事件的類型。StandardWatchEventKinds類定義了用於表示事件種類的常量,如下所示。
- ENTRY_CREATE
- ENTRY_DELETE
- ENTRY_MODIFY
- OVERFLOW
OVERFLOW表示丟失或丟棄的事件。創建觀察服務用來觀察目錄,以進行進一步更改。
WatchService ws = FileSystems.getDefault().newWatchService();
要使用Watch服務註冊目錄,請使用register()方法,該方法將返回一個WatchKey對象作爲註冊令牌。
// Get a Path object for C:\myName directory to watch
Path dirToWatch = Paths.get("C:\\myName");
WatchKey token = dirToWatch.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
要取消註冊,請使用WatchKey的cancel()方法。當註冊目錄時,其WatchKey處於就緒狀態。可以通過手錶服務註冊多個目錄。
要從監視服務隊列中檢索WatchKey,請使用WatchService對象的take()或poll()方法檢索並刪除發出信號並排隊的WatchKey。take()方法等待,直到WatchKey可用。poll()方法可用於爲等待指定超時時間值。
以下代碼使用無限循環來檢索發出信號的WatchKey。
while(true) {
WatchKey key = ws.take();
}
處理事件
WatchKey的pollEvents()方法檢索並刪除其所有掛起的事件。它返回一個WatchEvent的列表-List。List的每個元素代表WatchKey上的一個事件。
以下代碼顯示了處理事件的典型邏輯:
while(true) {
WatchKey key = ws.take();
// Process all events of the WatchKey
for(WatchEvent<?> event : key.pollEvents()) {
// Process each event here
}
}
處理事件後重置WatchKey
如果要重置WatchKey對象,通過調用它的reset()方法來再次接收事件通知。
reset()方法將WatchKey置於就緒狀態。如果WatchKey仍然有效,reset()方法返回true,否則它返回false。
如果WatchKey被取消或其監視服務關閉,它可能會失效。
// Reset the WatchKey
boolean isKeyValid = key.reset();
if (!isKeyValid) {
System.out.println("No longer watching " + dirToWatch);
}
WatchService是可自動關閉的。可以在try-with-resources塊中創建一個WatchService對象,當程序退出塊時,它會自動關閉。
示例
以下代碼顯示瞭如何實現監視服務以監視目錄中的更改。
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class Main {
public static void main(String[] args) {
try (WatchService ws = FileSystems.getDefault().newWatchService()) {
Path dirToWatch = Paths.get("C:\\myName");
dirToWatch.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
while (true) {
WatchKey key = ws.take();
for (WatchEvent<?> event : key.pollEvents()) {
Kind<?> eventKind = event.kind();
if (eventKind == OVERFLOW) {
System.out.println("Event overflow occurred");
continue;
}
WatchEvent<Path> currEvent = (WatchEvent<Path>) event;
Path dirEntry = currEvent.context();
System.out.println(eventKind + " occurred on " + dirEntry);
}
boolean isKeyValid = key.reset();
if (!isKeyValid) {
System.out.println("No longer watching " + dirToWatch);
break;
}
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}