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

Tea*_*azl 7 java windows watchservice

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

Ole*_*hin 8

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

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

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

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

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