I've been playing around with the java.nio.file.WatchService
and noticed that the Path
s returned from WatchEvent.context()
does not return correct .toAbsolutePath()
. Here is an example application:
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();
}
}
}
Example output:
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
It seems that the absolute path is resolved against the user.dir
system property instead of the Path
used for the WatchService
registration. That's a problem because when I try to use (for instance Files.copy()
) the path returned from the WatchEvent
I receive a java.nio.file.NoSuchFileException
, which is expected as there is no such file at this path. Am I missing something or this is a bug in the JRE ?
This is not a bug, but certainly confusing.
If WatchEvent.context()
returns a Path
then it is relative:
In the case of ENTRY_CREATE, ENTRY_DELETE, and ENTRY_MODIFY events the context is a Path that is the relative path between the directory registered with the watch service, and the entry that is created, deleted, or modified.
Now if you turn such a path into an absolute path by calling toAbsolutePath()
this happens not relative to the watched directory but to the default directory.
This method resolves the path in an implementation dependent manner, typically by resolving the path against a file system default directory. Depending on the implementation, this method may throw an I/O error if the file system is not accessible.
Therefore to turn the path into an absolute path you need to use
watchedDirectory.resolve(createdFile);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With