6

I'm having an issue with WatchService. Here is a snippet of my code:

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();

}

*First of all, know that watch() is called inside an infinite loop.

The problem is that when creating multiple files at a time, some events are missing. For example, if I copy-paste three files into the ".../request" folder, only one gets caught, the others remain as if nothing happened, neither an OVERFLOW event is triggered. In some different Computer and OS, it reaches up to two files, but if one tries 3 or more, the rest still untouched.

I found a workaround though, but I don't think it's the best practice. This is the flow:

The process starts and then stops at

WatchKey watckKey = watcher.take();

as expected, (as per Processing events). Then, I drop 3 files together in "request" folder, thus, process resumes at

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

The issue is here. It seems like the thread goes so fast through this line that two CREATED events stay behind and are lost, only one is taken. The workaround was to add an extra line right above this one, like this:

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

This seems to be a solution, at least for three and several more simultaneous files, but it's not scalable at all. So in conclusion, I would like to know if there is a better solution for this issue. FYI, I'm running a Win 7 64

Thanks a lot in advance!

4

2 回答 2

3

请务必重置您的 watchKey。上述一些答案没有,这也可以解释丢弃的事件。我推荐 Oracle 官方文档中给出的示例:https ://docs.oracle.com/javase/tutorial/essential/io/notification.html

请注意,即使正确使用,文件服务的可靠性也很大程度上取决于底层操作系统。一般来说,它应该被认为是一种不提供 100% 保证的尽力而为的机制。

于 2019-03-19T18:36:11.423 回答
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);
    });
}
于 2018-01-31T06:27:20.403 回答