我尝试将一个非常小的文件复制并粘贴到一个监视服务所观察的文件夹中。第一次运行很好,但在所有后续的复制和粘贴操作,我得到一个异常,另一个进程已经处理该文件。通过实验,我发现在Windows创建文件时通知我的服务,而不是在复制内容时通知我的服务。如果我锁定文件,Windows无法复制任何数据,文件为空。另一方面,如果我将文件移动到目录中,一切正常。
这是Windows的错误吗?我无法在mac或Linux工作站上测试它。或者也许只是我无能为力。任何帮助表示赞赏。
我的代码如下所示:
try (WatchService watchService = importPath.getFileSystem().newWatchService()) {
importPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
handleExistingFiles();
try {
do {
WatchKey watchKey = watchService.take();
if (!watchKey.isValid()) {
continue;
}
boolean hasCreationEvents = false;
for (WatchEvent<?> event : watchKey.pollEvents()) {
hasCreationEvents |= event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE);
}
watchKey.reset();
if (hasCreationEvents) {
handleNewFiles();
}
}
while (!Thread.currentThread().isInterrupted());
}
catch (InterruptedException ignoredEx) {
Thread.currentThread().interrupt();
}
}
答案 0 :(得分:7)
复制操作并非总是原子的。
使用原子复制(或移动),您将获得一个ENTRY_CREATE事件,该事件引用的文件将完整并可供阅读。
如果副本不是原子的,则在创建文件时将收到ENTRY_CREATE事件,然后在复制操作写入文件时您将收到一个或多个ENTRY_MODIFY事件。
没有简单的方法可以确定复制操作何时写入文件并将其释放。根据操作系统和文件系统的不同,在复制操作锁定文件时尝试打开文件进行读取时可能会出现FileNotFoundException,或者您可以成功打开文件,但实际读取时会得到部分内容。
您必须实施一些启发式方法,例如在ENTRY_CREATE之后立即尝试读取文件,并在初次读取失败时重新安排读取时间。