当文件系统中的对象被修改时,我们可以监听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();
}
}
}