Java:在复制内容之前,WatchService会得到通知

8
我尝试将一个非常小的文件复制粘贴到被监视的文件夹中。第一次操作很顺利,但在后续的所有操作中,我都会收到一个异常,说另一个进程已经处理了该文件。通过实验,我发现我的服务是在Windows创建文件时得到通知,而不是在复制其内容时得到通知。如果我锁定文件,Windows 就无法复制任何数据,文件也会变为空文件。另一方面,如果我将文件移动到目录中,一切都正常。
这是 Windows 的 bug 吗?我无法在 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();
  }
}

哪些程序创建了你所观看的文件?不要忘记,很多时候,程序会先写入临时文件,然后才覆盖原始文件。 - fge
这是我们的一个旧程序,它创建一个输出文件以传输数据到当前程序。我会检查文件的写入方式,但正如Oleg在下面提到的,问题可能是两个事件同时发生,一个用于创建,一个用于修改,而我回应了错误的事件... - Teazl
1个回答

10

复制操作并不总是原子性的。

使用原子复制(或移动)将会收到一个单独的ENTRY_CREATE事件,该事件引用的文件将完整并可供阅读。

如果复制不是原子性的,则在创建文件时将收到一个ENTRY_CREATE事件,然后在复制操作写入文件时会收到一个或多个ENTRY_MODIFY事件。

没有简单的方法来确定复制操作何时完成对文件的写入并释放它。根据操作系统和文件系统的不同,在复制操作锁定文件时尝试打开文件进行阅读可能会得到FileNotFoundException,或者当您实际阅读文件时,您将只能获得部分内容。

您将需要实现一些启发式算法,例如在ENTRY_CREATE后立即尝试读取文件,并在初始读取失败时重新安排读取的时间。


1
谢谢提示。我将代码从ENTRY_CREATE更改为ENTRY_MODIFY,并且没有遇到任何问题,至少在Windows上是这样。我将检查其他操作系统并希望它们也能正常工作。处理完文件后,它将被删除。我想那就可以了 :) - Teazl
我已经在MAC系统上测试过了,它也可以正常工作。非常感谢! - Teazl

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