WatchService - 错误解析绝对路径

Sve*_*rev 3 java nio java.nio.file watchservice

我一直在玩,java.nio.file.WatchService并注意到Path返回的s WatchEvent.context()不会返回正确的.toAbsolutePath().这是一个示例应用程序:

public class FsWatcher {
  public static void main(String[] args) throws IOException, InterruptedException {
    if (args.length != 1) {
      System.err.println("Invalid number of arguments: " + args.length);
      return;
    }
    //Run the application with absolute path like /home/<username>
    final Path watchedDirectory = Paths.get(args[0]).toAbsolutePath();
    final FileSystem fileSystem = FileSystems.getDefault();
    final WatchService watchService = fileSystem.newWatchService();
    watchedDirectory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

    while (true) {
      WatchKey watchKey = watchService.take();
      for (WatchEvent<?> watchEvent : watchKey.pollEvents()) {
        if (watchEvent.kind().equals(StandardWatchEventKinds.OVERFLOW)) {
          continue;
        }

        final Path createdFile = (Path) watchEvent.context();
        final Path expectedAbsolutePath = watchedDirectory.resolve(createdFile);
        System.out.println("Context path: " + createdFile);
        System.out.println("Context absolute path: " + createdFile.toAbsolutePath());
        System.out.println("Expected absolute path: " + expectedAbsolutePath);
        System.out.println("usr.dir: " + System.getProperty("user.dir"));
      }
      watchKey.reset();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

Context path: document.txt
Context absolute path: /home/svetlin/workspaces/default/FsWatcher/document.txt
Expected absolute path: /home/svetlin/document.txt
usr.dir: /home/svetlin/workspaces/default/FsWatcher
Run Code Online (Sandbox Code Playgroud)

似乎绝对路径是针对user.dir系统属性而不是Path用于WatchService注册的.这是一个问题,因为当我尝试使用(例如Files.copy())从WatchEvent我收到a 返回的路径时java.nio.file.NoSuchFileException,由于此路径中没有此类文件,因此可以预期.我错过了什么,或者这是JRE中的错误?

wer*_*ero 9

这不是一个错误,但肯定令人困惑.

如果WatchEvent.context()返回a Path那么它是相对的:

对于ENTRY_CREATE,ENTRY_DELETE和ENTRY_MODIFY事件,上下文是Path,它是向watch服务注册的目录与创建,删除或修改的条目之间的相对路径.

现在,如果通过调用toAbsolutePath()此方法将此路径转换为绝对路径,则不是相对于监视目录而是相对于默认目录.

此方法通常通过针对文件系统缺省目录解析路径,以依赖于实现的方式解析路径.根据实现,如果文件系统不可访问,此方法可能会抛出I/O错误.

因此,要将路径转换为您需要使用的绝对路径

watchedDirectory.resolve(createdFile);
Run Code Online (Sandbox Code Playgroud)

  • 如果像我一样,你在一个事件循环中混合被监视的目录(因此冒着在不同目录中使用相同名称的多个文件的风险,那么能够获得当前密钥评估的目录是有用的: `((Path)key.watchable()).resolve(((WatchEvent <Path>)event).context())` (3认同)
  • 老实说,我认为这绝对是一个错误。我得到了一个相对于错误目录的文件的绝对路径,这肯定会导致异常。当我调用 toAbsolutePath() 时,我希望获得刚刚创建的文件(实际存在的文件)的完整路径,而不是不存在的文件。 (2认同)