Java NIO2 – Watching a directory for changes
Java NIO2 WatchService was introduced in Java 7 as part of the NIO2. WacthService provides the ability for monitoring a file or directory for change.
In this articles, we will explore this exciting yet less known feature introduced under Java 7 NIO.
1. Introduction
WatchService
can also be called as notification API, It allows the user to register directory(s) with the service with the ability for us to define a type of event we are interested (like file creation, deletion etc. ), it will notify user when it will detect change in the directory(s).
e.g. Let’s say you want to detect any if a new file(s) are being created in a given directory, you can use WacthService
to register this directory and tell service to notify you if a new file is being created.
Most of the modern IDE provide such feature which enables them to detect any file change happening in the workbench (Have you ever seen a popup indicating file has been changed, please update ). If we want to implement a similar feature, we can create a polling API but the solution might not be perfect.
Java 7 NIO2 WacthService is a scalable solution to achieve above objectives.
2. WatchService Overview
The first step is to create a WatchService instance using FileSystems class
WatchService watchService = FileSystems.getDefault().newWatchService();
Register all directories with WatchService, which we are planning to monitor, during this registration we also need to specify what kind of event we are interested in
Path directory = Paths.get("/Users/umesh/personal/tutorials/source");
WatchKey key = directory.register(watchService,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
Pay close attention to following 2 points
- Path’s register method took WatchService as the first method
- The second argument to the method is of type StandardWatchEventKinds, which indicates what kind of event we are interested.
We can only register Watchable interface with WacthService and since Path class implements it, so this directory/path got registered with WacthService.
3. StandardWatchEventKinds
While registering with WacthService, we need to specify what event(s) we are interested in. You can pass any or all of the following value during registration.
Event Name | Description |
ENTRY_CREATE |
Triggered when a new entry is created in the watched directory (file or directory creation). |
ENTRY_DELETE |
Triggered when an entry is deleted/ moved in watched directory. |
ENTRY_MODIFY |
Triggered when an entry is modified in the watched directory. |
OVERFLOW |
Indicates that events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it. |
You won’t be able to register individual files in WacthService. Service will throw NotDirectoryException
in case you will register files with WacthService.
3. WatchKey
When we register with WacthService, it returned WacthKey as a token, WacthKey contains certain state.
- When we first register with WatchService, WacthKey will be in ready state.
- In the case of an event, the key is signaled and queued so that it can be retrieved.
- WatchKey will remain in the same state until we call reset method.
4. Processing Event
WatchService do not have any callback feature, it provided number of different ways to poll for getting this information
WatchKey pollEvent= watchService.poll();
poll()
method will return queued key if available or will return null if unavailable.
WatchKey watchKey = watchService.poll(long timeout, TimeUnit units);
Above will return key immediately if available, in case it is not available, API will wait till the time specified in “timeout” parameter.
If we want to wait till the event occurred, We can use wait() method of the API. This method will return key immediately (if available) else it will wait for the event
WatchKey wait = watchService.take();
For WacthService to work correctly, we need to put the event back in the ready state once it has been processed. Call reset method on the WacthKey to reset it
key.reset();
In order to process rest of events, we need to fetch List of WatchEvent from the pollEvent()
method. Here is a small example indicating how to handle and process these events in a real life use case.
WatchKey wait;
while ((wait = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == ENTRY_CREATE) {
//handle create
}
if (event.kind() == ENTRY_DELETE) {
//handle delete
}
}
}
5. Complete Example
package com.umeshawasthi.tutorials.corejava.io.nio2;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import static java.nio.file.StandardWatchEventKinds.*;
/**
* Created by umesh on 6/15/17.
*/
public class NIOWatchService {
public static void main(String[] args) throws IOException, InterruptedException {
WatchService watchService = FileSystems.getDefault().newWatchService();
Path directory = Paths.get("/Users/umesh/personal/tutorials/source");
directory.register(watchService,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == ENTRY_CREATE) {
//handle create
}
if (event.kind() == ENTRY_DELETE) {
//handle delete
}
System.out.println(event.kind()+ " Event Happened on "+event.context());
}
key.reset();
}
}
}
When we run this program and done some changes in the source directory, we saw following output
ENTRY_MODIFY Event Happened on index2.html
ENTRY_MODIFY Event Happened on .DS_Store
ENTRY_CREATE Event Happened on untitled folder
ENTRY_MODIFY Event Happened on .DS_Store
ENTRY_CREATE Event Happened on WatchService
ENTRY_DELETE Event Happened on untitled folder
6. When to Use WatchService
Watch Service API provides really some interesting features and can be used in following places easily
- Processing files (e.g. Processing product price file), If price file is dropped in the directory, it will notify custom program to process it.
- An application server that watches a directory, waiting for some file to redeploy.
In this article, we explore one of the interesting feature introduced under Java 7 NIO Package. We explored various features of WatchService API and discussed how to use the different poll method to get information about the event. We also created a complete example to demonstrate how all these pieces work together.
All the code of this article is available Over on Github. This is a Maven-based project.
References
Comments are closed.