WatchService(Windows 7):删除文件时,它会触发ENTRY_MODIFY和ENTRY_DELETE事件吗?

5
在使用WatchService时,我发现如果我删除正在被监视的目录中的文件,它将会触发一个ENTRY_MODIFY事件,然后是一个ENTRY_DELETE事件。
我知道从技术上讲,在删除之前文件可能会被修改,但是删除文件将触发ENTRY_MODIFY事件(这可能没人关心),这真的是期望的行为吗?
为了解决这个问题,我不得不添加一个条件来检查是否需要传递ENTRY_MODIFY事件。
            if (eventKind == ENTRY_CREATE) {
                listener.fileCreated(file);
            } else if (eventKind == ENTRY_MODIFY) {
                if (Files.exists(fullPath, LinkOption.NOFOLLOW_LINKS)) {
                    listener.fileChanged(file);
                }
            } else if (eventKind == ENTRY_DELETE) {
                listener.fileDeleted(file);
            }

有没有更好的方法来处理这个问题(功能)?


1
我认为这是预期的,而你正在使用的处理这种行为的单行代码对我来说似乎是一个简单的解决方案。 - colti
@colti:我还没有在Linux上测试的机会。这里Windows和Linux之间的行为有什么区别吗? - Sam Goldberg
1
可能是可以的,但我不确定。Linux实现使用inotify,如果您想了解更多信息,请参阅:http://man7.org/linux/man-pages/man7/inotify.7.html - colti
在我的机器上,当接收到ENTRY_MODIFY事件后,Files.exists()会返回true,除非等待大约10毫秒,这使得它极不可靠。难道没有更好的方法吗? - Fulluphigh
我正在Windows 7下运行,并发现WatchService在删除时的行为非常不可靠。有时我删除文件时会得到ENTRY_MODIFIED和ENTRY_DELETE,而其他时候我只会得到一个ENTRY_MODIFIED。正如@Fulluphigh所提到的,检查文件是否存在也是不可靠的。我使用Java 1.8 vm运行,但编译为1.7。 - David Bradley
1个回答

2
我只能证实这个问题。从评论和我的观察来看,ENTRY_MODIFY事件在文件被删除之前触发,你需要处理它。
假设我们有两个线程。一个正在执行Files.delete(),另一个正在监视目录并尝试读取修改过的文件。以下任何一种情况都可能发生:
1. Files.delete() 在事件被监视线程捕获之前刚好修改和删除了该文件。然后,在ENTRY_MODIFY之后检查文件是否存在的技术可以起作用。 2. Files.delete()调用可能失败(返回false),因为文件已被监视线程打开。
唯一的解决方法似乎是在监视线程中忽略所有IOExceptions并多次重试Files.delete()调用。
我只尝试使用Files.delete()从同一JVM中删除文件。我没有尝试从系统上的其他进程中删除。问题在Windows 7~10上的NTFS上复现,可能不适用于其他操作系统。
我鼓励其他人编辑此答案并添加他们的观察结果。

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