【问题标题】:Why there is a delay in detecting a file change using WatchService? (Java)为什么使用 WatchService 检测文件更改会有延迟? (爪哇)
【发布时间】:2012-11-19 05:24:03
【问题描述】:

我有一个应用程序,当文件被添加到目录时,WatchService 会检测到该文件并将该文件添加到文件列表中以供进一步处理。这是我的代码

 public void run() {

    /*
     * Goes in an infinite loop
     */
     while(!finished) {

     /*
      *  Get a watch key, poll() returns a queued key 
      *  if no queued key, this method waits until the specified time.
      */
     WatchKey key;
     try {
             key = watcher.poll(eofDelay,TimeUnit.MILLISECONDS);
      } catch (InterruptedException x) {
          return;
      }

     Path dir = keys.get(key);

     if (dir == null) {
         continue;
      }

     Path child=null;

         /*
          * Fetching the list of watch events from
          * pollEvents(). There are four possible events
          */

         for (WatchEvent<?> event: key.pollEvents()) {
            WatchEvent.Kind kind = event.kind();

            /*
             * Overflow indicates that events 
             * might have been lost or discarded
             */
             if (kind == OVERFLOW) {
                 continue;
             }


             WatchEvent<Path> ev = cast(event);

             /*
              * Filename is the context of the event
              */
             Path name = ev.context();

             /*
              * Resolves the name of the file to a path
              */
              child = dir.resolve(name);

             /*
              *  If directory is created, and watching recursively, then
              * register it and its sub-directories
              */
             if (nested && (kind == ENTRY_CREATE)) {
                 try {
                     if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                         registerAll(child);
                     }
                 } catch (IOException x) {

                 }
             }
         }

         File file = child.toFile();

         /*
          * Only add the file if there is no wild card 
          * or it matches the specified wild card 
          */
         if (matcher == null || matcher.matches(file.toPath().getFileName())) {
             fileList.add(file);
         }
     /*
      * Key is reset so that it can receive further
      * events 
      */

         boolean valid = key.reset();
         if (!valid) {
             keys.remove(key);

            /*
             * If key is no longer valid and empty,
             * exit the loop
             */
             if (keys.isEmpty()) {
                continue;
             }
         }

     }
 }

此代码按预期工作,但我正在设计一个高性能应用程序,它以非常高的速度处理文件中的数据。所以这里的问题是检测文件所用的时间不一致。例如,最初目录中有一些文件,它们由应用程序处理,现在当添加新文件时,检测文件需要 4-5 秒,有时需要 2 秒或 20 毫秒等。我的 eofDelay 值为 10 毫秒。这种不一致的原因是什么?有没有办法增强这个实现?或者任何其他可用于目录更改的高效库?我希望检测文件所花费的时间最少且一致,花费一秒钟以上的时间非常昂贵。在这方面的任何帮助将不胜感激。 :)

【问题讨论】:

  • 我建议(在适用的情况下)您受底层操作系统和文件系统的支配。可能会出现延迟,因为“批处理”更新调用的功能正在等待合适的时间来调度事件 - 这个猜想,我过去只使用过 JNI 这种类型的解决方案,并且总是存在某种延迟.
  • @MadProgrammer 哦,我明白了,也许我应该尝试 JNI 并使用具有一致延迟的那个。
  • 我认为你最终还是会遇到同样的问题 - 恕我直言
  • 你在使用 OSX 吗?我们看到它的延迟在 Ubuntu 中按预期工作,但在 OSX 上最多延迟 5 秒。
  • stackoverflow.com/questions/9588737/… --> 第二个答案对我有用,延迟明显减少,即使它不如 Ubuntu 系统好

标签: java watchservice


【解决方案1】:

您可以通过在文件夹中添加敏感度标志来获得更快的结果(见下文)。

// copied from http://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-else
folder.register(watcher, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH); 

但是,您仍将受制于底层操作系统。我见过的大多数文件监视应用程序在添加文件和拾取文件之间都有几秒钟的延迟。您在应用程序中看到了正常的延迟时间。

如果您的应用程序必须在几毫秒内响应添加的几个文件,则不应使用 Java(NIO 或其他),而应使用 C/C++。这将大大增加您的代码的复杂性。

【讨论】:

  • WatchServices 是高度优化的。在Windows 上,它使用ReadDirectoyChangesW,它的效率最高。在 Linux 它尝试使用 iNotify。
  • 感谢您的链接。我在 Windows 上使用过 NIO,看到的和原来的海报一样。您是否有明显不同的第一手资料?
  • 您尝试使用本地目录还是共享目录? (共享需要 SMB3 Windows 8)才能高效。
  • 我用的是本地FS。有时我几乎会立即收到一条消息,有时我会在一两秒后收到一条消息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多