Using the java.nio watching service, I try to watch a directory and all of its subdirectories:
Files.walkFileTree(projectPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
watched.put(key, new WatchableDirectory(dir, projectPath));
return FileVisitResult.CONTINUE;
}
});
Then I wait for events:
executor.submit(new Runnable() {
@Override
public void run() {
try {
WatchKey key;
while ((key = watcher.take()) != null) {
List<WatchEvent<?>> events = key.pollEvents();
WatchableDirectory watchableDirectory = watched.get(key);
for (WatchEvent<?> event : events) {
....
}
}
....
}
}
(watched
is a Map
that holds mappings from a key to metadata about the directory)
However, only the first event for a given directory is fired. Whenever I change another file in a directory, where a file has already been changed, nothing happens (I validate that by both putting a breakpoint and expecting the logic in the for-loop to take place).
However, if I modify a file in another directory, then everything works (again, only the first time).
No exceptions are thrown (there is a catch clause for java.lang.Exception
), and the loop obviously continues to run.
I thought that probably once consumed, the directory might be deregistered. So I added a line to re-register it after its file is being handled. No effect.
Windows 7, Java 7.
Any ideas why?
Don't forget to call
key.reset();
after you are done using it in your while
loop.
The docs state
Otherwise if there are pending events for the object then this watch key is immediately re-queued to the watch service. If there are no pending events then the watch key is put into the ready state and will remain in that state until an event is detected or the watch key is cancelled.
and
Watch keys are safe for use by multiple concurrent threads. Where there are several threads retrieving signalled keys from a watch service then care should be taken to ensure that the reset method is only invoked after the events for the object have been processed. This ensures that one thread is processing the events for an object at any time.
So if you don't reset, it's as if your watch is disabled.
WatchKey#reset()
returns a boolean value for if it is valid or not. Handle that case as explained in the tutorial.
Marko emphasises:
After the events for the key have been processed, you need to put the key back into a ready state by invoking reset. If this method returns false, the key is no longer valid and the loop can exit. This step is very important. If you fail to invoke reset, this key will not receive any further events.
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