WatchService:遗漏和未处理事件

6
我在使用WatchService时遇到了问题。这是我的一段代码片段:
public void watch(){
  //define a folder root
  Path myDir = Paths.get(rootDir+"InputFiles/"+dirName+"/request");      

  try {
    WatchService watcher = myDir.getFileSystem().newWatchService();
    myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); 

    WatchKey watckKey = watcher.take();

    List<WatchEvent<?>> events = watckKey.pollEvents();
    for (WatchEvent event : events) {
      //stuff
    }
  }catch(Exception e){}

  watckKey.reset();

}

首先,了解到watch()是在一个无限循环中调用的。

问题在于当同时创建多个文件时,有些事件会丢失。例如,如果我将三个文件复制粘贴到“.../request”文件夹中,只有一个文件被捕获,其他文件则像什么都没有发生一样,也不会触发OVERFLOW事件。在某些不同的计算机和操作系统上,最多可以捕获两个文件,但如果尝试3个或更多文件,则其余文件仍然无法触发。

我找到了一个解决方法,但我不认为它是最佳实践。这是流程:

进程开始,然后停在

WatchKey watckKey = watcher.take();

如预期的那样(根据处理事件),然后我将三个文件一起放入“请求”文件夹中,因此,处理过程在此恢复。

List<WatchEvent<?>> events = watckKey.pollEvents();

问题出在这里。看起来线程通过这行的速度非常快,导致两个“CREATED”事件滞后并丢失,只有一个被接受。解决方法是在这一行的正上方添加一行额外的代码,就像这样:
Thread.sleep(1000);
List<WatchEvent<?>> events = watckKey.pollEvents();

这似乎是一个解决方案,至少对于三个或更多个同时打开的文件来说是有效的,但它根本不具备可扩展性。
总之,我想知道是否有更好的解决方案。顺便提一下,我正在运行 Win 7 64。
非常感谢您的帮助!
2个回答

4

请确保重置您的watchKey。其中一些回答未重置,这可能会导致事件丢失。我建议参考官方Oracle文档中给出的示例:https://docs.oracle.com/javase/tutorial/essential/io/notification.html

请注意,即使正确使用,文件服务的可靠性也严重依赖于底层操作系统。通常,应将其视为尽力而为的机制,无法百分之百保证。


2

如果在无限循环中调用watch,则会创建无限次的watch服务,因此有可能会丢失事件。我建议按照以下方式进行操作:仅调用一次watchservice方法:

public void watchservice()
{
    Thread fileWatcher = new Thread(() ->
    {
        Path path = Paths.get(rootDir+"InputFiles/"+dirName+"/request");
        Path dataDir = Paths.get(path);       

        try 
        {
            WatchService watcher = dataDir.getFileSystem().newWatchService();
            dataDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);

            while (true)
            {
                WatchKey watckKey;
                try
                {
                    watckKey = watcher.take();
                }
                catch (Exception e)
                {
                    logger.error("watchService interupted:", e);
                    return;
                }
                List<WatchEvent<?>> events = watckKey.pollEvents();
                for (WatchEvent<?> event : events) 
                {
                    logger.debug("Event Type : "+ event.kind()  +" , File name found :" + event.context());
                    if (event.kind() != StandardWatchEventKinds.OVERFLOW) 
                    {
                        // do your stuff
                    }
                }
            }
        }
        catch (Exception e) 
        {
            logger.error("Error: " , e);
        }
    });
    fileWatcher.setName("File-Watcher");
    fileWatcher.start();

    fileWatcher.setUncaughtExceptionHandler((Thread t, Throwable throwable) -> 
    {
        logger.error("Error ocurred in Thread " + t, throwable);
    });
}

1
在我的编码过程中,我做了这件事,将手表服务创建从无限循环中取出。我不记得确切的原因,也没有再尝试这种情况。不过解决方法仍然存在。 - McCoy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接