简体   繁体   English

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

[英]Event fired only once when watching a directory

Using the java.nio watching service, I try to watch a directory and all of its subdirectories: 使用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;
    }
});

Then I wait for events: 然后我等待事件:

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 is a Map that holds mappings from a key to metadata about the directory) watched是一个Map ,它包含从键到映射关于目录的元数据的映射)

However, only the first event for a given directory is fired. 但是,仅触发给定目录的第一个事件。 Whenever I change another file in a directory, where a file has already been changed, nothing happens (I validate that by both putting a breakpoint and expecting the logic in the for-loop to take place). 每当我更改目录中的另一个文件时,文件已经被更改,没有任何反应(我通过设置断点并期望for循环中的逻辑发生来验证)。

However, if I modify a file in another directory, then everything works (again, only the first time). 但是,如果我修改另一个目录中的文件,那么一切正常(再次,只是第一次)。

No exceptions are thrown (there is a catch clause for java.lang.Exception ), and the loop obviously continues to run. 没有抛出异常( java.lang.Exception有一个catch子句),循环显然继续运行。

I thought that probably once consumed, the directory might be deregistered. 我认为可能一旦消耗,该目录可能会被注销。 So I added a line to re-register it after its file is being handled. 所以我在处理文件后添加了一行来重新注册它。 No effect. 没有效果。

Windows 7, Java 7. Windows 7,Java 7。

Any ideas why? 有什么想法吗?

Don't forget to call 别忘了打电话

key.reset();

after you are done using it in your while loop. 在你的while循环中使用它之后。

The docs state 文档陈述

Otherwise if there are pending events for the object then this watch key is immediately re-queued to the watch service. 否则,如果对象存在待处理事件,则此监视密钥将立即重新排队到监视服务。 If there are no pending events then the watch key is put into the ready state and will remain in that state until an event is detected or the watch key is cancelled. 如果没有待处理事件,则表键处于就绪状态并将保持该状态,直到检测到事件或取消监视键。

and

Watch keys are safe for use by multiple concurrent threads. 监视密钥可以安全地由多个并发线程使用。 Where there are several threads retrieving signalled keys from a watch service then care should be taken to ensure that the reset method is only invoked after the events for the object have been processed. 如果有多个线程从监视服务检索已发出信号的密钥,则应注意确保仅在处理完对象的事件后调用reset方法。 This ensures that one thread is processing the events for an object at any time. 这可确保一个线程随时处理对象的事件。

So if you don't reset, it's as if your watch is disabled. 因此,如果您不重置,就好像您的手表被禁用一样。

WatchKey#reset() returns a boolean value for if it is valid or not. WatchKey#reset()返回一个布尔值,如果它是否有效。 Handle that case as explained in the tutorial . 按照教程中的说明处理该案例。

Marko emphasises: 马可强调:

After the events for the key have been processed, you need to put the key back into a ready state by invoking reset. 处理完密钥事件后,需要通过调用reset将密钥恢复到就绪状态。 If this method returns false, the key is no longer valid and the loop can exit. 如果此方法返回false,则该键不再有效,并且循环可以退出。 This step is very important. 这一步非常重要。 If you fail to invoke reset, this key will not receive any further events. 如果您未能调用reset,则此键不会再接收任何事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM