使用java.nio观看服务,我尝试观察目录及其所有子目录:
Files.walkFileTree(projectPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
watched.put(key, new WatchableDirectory(dir, projectPath));
return FileVisitResult.CONTINUE;
}
});
然后我等待事件:
executor.submit(new Runnable() {
@Override
public void run() {
try {
WatchKey key;
while ((key = watcher.take()) != null) {
List<WatchEvent<?>> events = key.pollEvents();
WatchableDirectory watchableDirectory = watched.get(key);
for (WatchEvent<?> event : events) {
....
}
}
....
}
}
(watched
是一个Map
,它包含从密钥到关于目录的元数据的映射。
但是,仅触发给定目录的第一个事件。每当我更改目录中的另一个文件时,文件已经被更改,没有任何反应(我通过放置断点并期望for循环中的逻辑进行验证)。
但是,如果我修改另一个目录中的文件,那么一切都有效(再次,只是第一次)。
不抛出异常(java.lang.Exception
有一个catch子句),循环显然继续运行。
我认为可能一旦消费,该目录可能会被取消注册。所以我在处理文件后添加了一行来重新注册它。没效果。
Windows 7,Java 7.
任何想法为什么?
答案 0 :(得分:24)
不要忘记致电
key.reset();
在while
循环中完成使用后
。
docs州
否则,如果该对象有待处理事件,那么此监视 密钥立即重新排队到监视服务。如果没有 挂起事件然后将监视键置于就绪状态并且将 保持该状态直到检测到事件或监视键 取消。
和
监视密钥可以安全地供多个并发线程使用。哪里 有几个线程从手表中检索信号键 服务然后应该注意确保重置方法 仅在处理了对象的事件后调用。这个 确保一个线程正在处理任何对象的事件 时间。
因此,如果您不重置,就好像您的手表被禁用一样。
WatchKey#reset()
返回一个布尔值,如果它是否有效。按照tutorial。
Marko强调:
处理完密钥事件后,需要将其放入 通过调用reset键将键恢复到就绪状态。如果此方法返回 false,键不再有效,循环可以退出。这一步是 很重要。如果您未能调用重置,则不会收到此密钥 任何进一步的事件。