在观看目录时,事件仅被触发一次

时间:2013-11-24 20:25:29

标签: java nio

使用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.

任何想法为什么?

1 个答案:

答案 0 :(得分:24)

不要忘记致电

key.reset();

while循环中完成使用后

docs

  

否则,如果该对象有待处理事件,那么此监视   密钥立即重新排队到监视服务。如果没有   挂起事件然后将监视键置于就绪状态并且将   保持该状态直到检测到事件或监视键   取消。

  

监视密钥可以安全地供多个并发线程使用。哪里   有几个线程从手表中检索信号键   服务然后应该注意确保重置方法   仅在处理了对象的事件后调用。这个   确保一个线程正在处理任何对象的事件   时间。

因此,如果您不重置,就好像您的手表被禁用一样。

WatchKey#reset()返回一个布尔值,如果它是否有效。按照tutorial

中的说明处理该案例

Marko强调:

  

处理完密钥事件后,需要将其放入   通过调用reset键将键恢复到就绪状态。如果此方法返回   false,键不再有效,循环可以退出。这一步是   很重要。如果您未能调用重置,则不会收到此密钥   任何进一步的事件。