如果本机事件通知机制不可用,则默认实现将使用轮询。 结果,响应性,事件的顺序和可用细节是特定于实现的。 (注意:有一篇有关使用Guava EventBus处理WatchService事件的文章 )
观看目录
Path接口实现了将WatchService对象和WatchEvent.Kind类型的varargs作为参数的register方法。 有4个事件需要注意:
- ENTRY_CREATE
- ENTRY_DELETE
- ENTRY_MODIFY
- 溢出
前三种是不言自明的,而OVERFLOW则表示事件可能丢失或丢弃。 通过调用FileSystem.newWatchService()创建WatchService。 观看目录是通过在WatchService中注册Path对象来完成的:
import static java.nio.file.StandardWatchEventKinds.*;
Path path = Paths.get("/home");
WatchService watchService = FileSystems.getDefault().newWatchService();
WatchKey watchKey = path.register(watchService,ENTRY_CREATE,ENTRY_DELETE,ENTRY_MODIFY);
从示例中可以看到,register方法返回一个WatchKey对象。 WatchKey是表示在WatchService中注册路径的令牌。
WatchKey
作为注册过程的结果,WatchKey处于“就绪”状态,并被视为有效。 WatchKey保持有效,直到发生以下情况之一:
- WatchKey.cancel()被调用。
- 正在监视的目录不再可用。
- WatchService对象已关闭。
检查变更
当检测到更改时,WatchKey状态将设置为“已信号发送”,并将其放入队列中进行处理。 使WatchKeys脱离队列涉及调用WatchService.poll()或WatchService.take()。 这是一个基本示例:
private boolean notDone = true;
while(notDone){try{WatchKey watchKey = watchService.poll(60,TimeUnit.SECONDS);List<WatchEvent.Kind<?>> events = watchKey.pollEvents();for(WatchEvent event : events){...process the events}if(!watchKey.reset()){...handle situation no longer valid}}catch(InterruptedException e){Thread.currentThread().interrupt();}
在第5行上,我们调用pollEvents方法来检索此WatchKey对象的所有事件。 在第9行,您会注意到对reset方法的调用。 reset方法将WatchKey状态重新设置为“就绪”,并返回一个布尔值,指示WatchKey是否仍然有效。 如果有任何未决事件,则WatchKey将立即重新排队,否则它将保持就绪状态,直到检测到新事件。 在已取消或处于就绪状态的WatchKey上调用reset无效。 如果WatchKey在排队时被取消,它将在队列中扩大直到被取回。 如果目录已删除或不再可用,取消也会自动发生。
处理事件
现在我们已经检测到一个事件,我们如何确定:
- 事件发生在哪个目录? (假设注册了多个目录)
- 实际事件是什么? (假设收听多个事件)
- 事件的目标是什么,即创建,删除或更新了哪个Path对象?
跳到上一个示例的第6行,我们将从WatchKey和WatchEvent中解析所需的信息:
//WatchKey watchable returns the calling Path object of Path.registerPath watchedPath = (Path) watchKey.watchable();//returns the event typeStandardWatchEventKinds eventKind = event.kind();//returns the context of the eventPath target = (Path)event.context();
在第6行,我们看到了WatchEvent.context方法被调用。 如果事件是创建,删除或更新,并且该事件相对于监视目录,则context方法将返回Path对象。 重要的是要知道,当收到事件时,不能保证执行该操作的程序已经完成,因此可能需要一定程度的协调。
结论
WatchService是Java 7中新的java.nio.file包的一个非常有趣的功能。也就是说,WatchService需要牢记两件事:
- WatchService不会为监视目录的子目录拾取事件。
- 我们仍然需要轮询WatchService的事件,而不是接收异步通知。
为了解决上述问题,有一篇后续文章,使用Guava EventBus处理WatchService事件 。 感谢您的宝贵时间,在下一篇文章中见。
资源资源
- java.nio.file软件包,其中包含此处讨论的WatchService,WatchKey和WatchEvent对象。
- 演示WatchService的单元测试
参考: Java 7的新增功能: JCG合作伙伴提供的 WatchService 比尔·贝杰克(Bill Bejeck)在“ 编码随机思想”博客上。
翻译自: https://www.javacodegeeks.com/2012/02/java-7-watchservice.html