Watching a folder for changes

Let's start with a stub method that gets the Path of the folder that should be monitored for changes as an argument:

public void watchFolder(Path path) 
throws IOException, InterruptedException {
...
}

WatchService will notify us when any of the ENTRY_CREATE, ENTRY_DELETE, and ENTRY_MODIFY event types occur on the given folder. For this, we need to follow several steps:

  1. Create WatchService so that we can monitor the filesystem—this is accomplished via FileSystem.newWatchService(), as follows:
WatchService watchService 
= FileSystems.getDefault().newWatchService();
  1. Register the event types that should be notified—this is accomplished via Watchable.register():
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
For each watchable object, we receive a registration token as a WatchKey instance (watch key). We receive this watch key at registration time, but WatchService returns the relevant WatchKey every time an event is triggered.
  1. Now, we need to wait for incoming events. This is accomplished in an infinite loop (when an event occurs, the watcher is responsible for queuing the corresponding watch key for later retrieval and changing its status to signaled):
while (true) {
// process the incoming event types
}
  1. Now, we need to retrieve a watch key – there are at least three methods dedicated to retrieving a watch key:
    • poll(): Returns the next key from the queue and removes it (alternatively, it will return null if no key is present).
    • poll​(long timeout, TimeUnit unit): Returns the next key from the queue and removes it; if no key is present, then it waits for the specified timeout and tries again. If a key still isn't available, then it returns null.
    • take(): Returns the next key from the queue and removes it; if no key is present, then it will wait until a key is queued or the infinite loop is stopped:
WatchKey key = watchService.take();
  1. Next, we need to retrieve the pending events of a watch key. A watch key in signaled status has at least one pending event; we can retrieve and remove all the events of a certain watch key via the WatchKey.pollEvents() method (each event is represented by a WatchEvent instance):
for (WatchEvent<?> watchEvent : key.pollEvents()) {
...
}
  1. Then, we retrieve information about the event type. For each event, we can obtain different information (for example, the event type, number of occurrences, and context-specific information (for example, the filename that caused the event), which is useful for processing the event)):
Kind<?> kind = watchEvent.kind();
WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
Path filename = watchEventPath.context();
  1. Next, we reset the watch key. A watch key has a status that can be either ready (initial status at creation), signaled, or invalid. Once signaled, a watch key remains like this until we call the reset() method, which attempts to put it back in the ready status to accept the event's state. If the transition from signaled to ready (resume waiting events) was successful, then the reset() method returns true; otherwise, it returns false, which means that the watch key may be invalid. A watch key can be in an invalid state if it is no longer active (inactivity can be caused by explicitly calling the close() method of the watch key, closing the watcher, the directory was deleted, and so on):
boolean valid = key.reset();

if (!valid) {
break;
}
When there is a single watch key in an invalid state, then there is no reason to stay in the infinite loop. Simply call break to jump out of the loop.
  1. Finally, we close the watcher. This can be accomplished by explicitly calling the close() method of WatchService or relying on try-with-resources, as follows:
try (WatchService watchService
= FileSystems.getDefault().newWatchService()) {
...
}

The code that's bundled with this book glues all these snippets of code into a single class named FolderWatcher. The result will be a watcher that's capable of reporting the create, delete, and modify events that occurred on the specified path.

In order to watch the path, that is, D:/learning/packt, we just call the watchFolder() method:

Path path = Paths.get("D:/learning/packt");

FolderWatcher watcher = new FolderWatcher();
watcher.watchFolder(path);

Running the application will display the following message:

Watching: D:learningpackt

Now, we can create, delete, or modify a file directly under this folder and check the notifications. For example, if we simply copy-paste a file called resources.txt, then the output will be as follows:

ENTRY_CREATE -> resources.txt
ENTRY_MODIFY -> resources.txt

In the end, don't forget to stop the application, since it will run indefinitely (in theory).

Starting with this application, the source code bundled with this book comes with two more applications. One of them is a simulation of a video capture system, while the other is a simulation of a printer tray watcher. By relying on the knowledge that we've accumulated during this section, it should be pretty straightforward to understand these two applications without further details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset