8

我试图将一个非常小的文件复制并粘贴到监视服务观察到的文件夹中。第一次效果很好,但是在所有后续的复制和粘贴操作中,我得到一个异常,另一个进程已经处理了该文件。通过实验,我发现当 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();
  }
}
4

1 回答 1

10

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

使用原子复制(或移动),您将获得一个 ENTRY_CREATE 事件,并且该事件引用的文件将是完整的并且可供读取。

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

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

您将不得不实施一些启发式方法,例如尝试在 ENTRY_CREATE 之后立即读取文件,并在初始读取失败时重新安排读取时间。

于 2014-04-09T08:12:11.823 回答