Using the WatchService API
As mentioned on the previous page, filing system notifications are sent to
your Java application via the WatchService API. The API works in the following stages:
- you ask the filing system for an instance of WatchService;
- you take Path objects representing the directories you want to watch and ask them
to register themselves with your WatchService instance;
- usually in a separate thread, you poll the WatchService for notifications; calls to
poll for notifications block until a new notification comes in, at which point the polling
thread is "woken up" with the notification.
Getting an instance of WatchService
The first stage of using filing system notifications is to get an instance of
WatchService. You will generally do this by calling:
WatchService watcher = FileSystems.getDefault().newWatchService();
The watch service will then be ready to register paths (directories) with and
to poll for events.
Registering directories for modification notifications
Logically, you might then expect to call a method on your newly acquired
WatchService object to register particular directories with it. In
fact, registration happens the other way round: you call the register()
method on the Path objects representing the directories you wish
to listen for notifications on.
In practice, this means that you register a File object (representing
the directory you wish to listen for notifications on) as follows:
import static java.nio.file.StandardWatchEventKind.*;
...
public class MyWatcher {
private final WatchService watcher;
private final Map keyPaths =
new ConcurrentHashMap();
public void watchDir(File dir) throws IOException {
Path p = dir.toPath();
WatchKey key = p.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
keyPaths.put(key, p);
}
}
Notice that when registering the Path object (in this case derived from
a corresponding File object), we supply three constants to say which
types of events we wish to listen for. These constants are defined in
StandardWatchEventKind. (In case you're not familiar with the import static
syntax, added in Java 5, it allows you to "import" the definitions of static constants from a particular
class as though they were defined in your class, so that they can be referenced without
any class prefix.)
In reality, it is unlikely that you would only register for a subset of these
events. Even if you are only interested in "modifications",
some events you which logically think of as "modifications" may in reality be notified
to your application as creation/deletion events. Notably, the renaming of a file is
likely to be notified to your application as a deletion/creation pair.
The Path.register() method returns a WatchKey object. It is up to
us to associate this key with the original path registered if this is important to us.
Later on, our application will receive notifications of modifications relative to a particular
key, but we will not be able to retrieve the identity of the original directory: now is
our opportunity to record this information if we need it. Because we will typically
poll for modifications in another thread, we need access this map in a thread-safe
manner. Using a ConcurrentHashMap
is a good choice.
Listening for modifications
Now, we are ready to listen or "poll" for
file modifications.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.