WatchService - 解析绝对路径错误

7

我一直在尝试使用java.nio.file.WatchService并注意到从WatchEvent.context()返回的Path不会返回正确的.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();
    }
  }
}

示例输出:

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

似乎绝对路径是相对于系统属性 user.dir 解析的,而不是用于 WatchService 注册的 Path。这是个问题,因为当我试图使用(例如Files.copy())从 WatchEvent 返回的路径时,我收到了一个 java.nio.file.NoSuchFileException,这是预期的,因为在此路径上没有这样的文件。我错过了什么还是这是 JRE 中的一个错误?
1个回答

13

这不是一个 bug,但肯定令人困惑。

如果WatchEvent.context()返回的是一个Path,那么它是相对路径:

在ENTRY_CREATE、ENTRY_DELETE和ENTRY_MODIFY事件的情况下,上下文是一个路径,该路径是注册到监视服务的目录与创建、删除或修改的条目之间的相对路径。

现在,如果您通过调用toAbsolutePath()将此类路径转换为绝对路径,则其发生的位置不是相对于被监视的目录,而是相对于默认目录。

该方法以实现相关的方式解析路径,通常是根据文件系统默认目录解析路径。根据实现,如果文件系统无法访问,则此方法可能会抛出I/O错误。

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

watchedDirectory.resolve(createdFile);

4
如果像我一样,在一个事件循环中混合了观察的目录(因此有可能在不同的目录中有多个同名文件),那么能够获取当前键正在评估的目录是非常有用的:((Path) key.watchable()).resolve( ((WatchEvent<Path>) event).context() ) - Guus
2
我真的认为这绝对是一个 bug。我得到了一个相对于错误目录的文件的绝对路径,这肯定会导致异常。当我调用 toAbsolutePath() 时,我期望得到刚刚创建的文件(实际存在的文件)的完整路径,而不是一个不存在的文件。 - Cosmin Ioniță

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