乐趣区

NIO 之 WatchService

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(监控文件变化)
本文如有问题,欢迎在评论区中指正。

退出移动版