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(监控文件变化)
本文如有问题,欢迎在评论区中指正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。