Java 7 NIO 2 API's Watch Service - Notes and Example
Aug 10, 2013
This blog post is about using Java SE 7's Watch Service API. This includes an example, its description and notes on usage in applications.
This post's contents:
- Introduction
- The Example
- The Example's Output
- File Actions and Events
- Notes on usage of Watch Service in Applications
- WatchServiceExample1.java
- Download
- References
1. Introduction
java.nio.file
package has a file change notification API, called the Watch Service.
A watch service watches registered objects for changes and the resulting events. For example, a file manager application may use a watch service to monitor a directory for changes, so that it can update its display of the list of files when files are created, renamed or deleted.
The watch service usage overview steps:
- Register a directory with the watch service.
- Specify the type of events of interest in the directory, like file creation or deletion.
- When the watch service detects an event, it is queued (to the watch service) - and a consumer process (like an application's thread) can handle the events as required.
2. The Example
The following is an example application using the watch service. This describes the API's usage steps. The complete code WatchServiceExample1.java is listed at the end of this post.
2.1. Create a new watch service for the file system.
WatchService watchService = FileSystems.getDefault().newWatchService();
2.2. Get the directory path to be watched (monitored).
String watchedDir = "D:\\JavaWatchService\\testdir1";
Path dir = Paths.get(watchedDir);
2.3. Register the directory to be monitored with the watch service.
Register the object to be monitored with the watch service. This is the directory's path object. The registered object is required to implement the Watchable
interface. Path
is an interface, and extends the Watchable
.
WatchKey watchKey = dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
2.3.1. Watch Event Kinds:
The events parameter is the events (event identifiers) to register - ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY and OVERFLOW are the standard event kinds. These are defined in the StandardWatchEventKind
class, as fields of type WatchEvent.Kind<T>. One or all of these events can be specified.
The standard events (except OVERFLOW) are defined as WatchEvent.Kind<Path>. The context for these events is the relative path between this directory's path and the file path that is created, deleted, or modified.
The OVERFLOW is defined as WatchEvent.Kind<Object>. The OVERFLOW event need not be registered to receive it. This is a special event to indicate that events may have been lost or discarded.
2.3.2. Watch Key:
The register() method returns a WatchKey
object. The watch key is a token representing the registration of a Watchable
object (the directory's Path) with a watch service. WatchKey
is defined as an interface in the API.
This watch key is valid, and remains valid until cancelled or closed.
A watch key has 3 states - (1) a ready state when created and after it is reset, (2) a state at event detection and being signaled, and (3) a not valid state. All events are retrieved (and removed) from the watch key. The retrieved events are processed as required by an application.
At the end of processing all the events, the watch key is to be reset and ready (state) for the next set of the monitored watch service events.
A watch key is cancelled by using the cancel() method, by closing the watch service, or when not accessible.
Useful WatchKey
methods are: cancel(), reset() and pollEvents().
2.4. Get and process the events that occur.
The events occur when the registered directory has changes. The events are queued. The consumer process using the watch service invokes the take() or poll() methods. These methods return the watch key with these events.
2.4.1. Wait for the watch key to be signaled of events.
watchKey = watchService.take();
There are three WatchService
methods to get the watch key with the queued events:
- poll(): The method returns immediately with a watch key (if available) or a null value (if not available).
- poll(long timeunits, TimeUnit): The method returns a watch key or a null value. The method waits until the specified time period, if a watch key is not immediately available.
- take(): This method returns a watch key when available, otherwise waits.
2.4.2. Get and process the events for the watch key.
(i) Get the list of events from the watch key. The WatchKey
's pollEvents() method returns the events (watch events) as a List collection of type WatchEvent<?>
.
List<WatchEvent<?>> eventList = watchKey.pollEvents();
(ii) Iterate over the list of events and process each event.
for (WatchEvent<?> genericEvent : eventList) {
Process the event kinds, one at a time, as required. The WatchEvent
's kind() method returns the event kind (WatchEvent.Kind
).
If (genericEvent.kind()== OVERFLOW) {
// do something, like process the next event in the event list
}
In case of the standard events other than the OVERFLOW, the file Path (and the file name) associated with the event can be retrieved, using the WatchEvent
's context() method.
if (genericEvent.kind() == ENTRY_CREATE) {
// do something as required
Path filePath = (Path) genericEvent.context();
}
NOTE: A cast is required to the Path
. The context (the context object associated with the event) of the genericEvent (WatchEvent<?>
) is of generic type parameter ?. And the WatchEvent.Kind<type parameter>
for the standard (non OVERFLOW) event is of type Path
.
(iii) Process the next iterator element - the next event (ii).
2.4.3. Reset the watch key.
At this point, all events for the watch key are processed. Reset the watch key.
boolean validKey = watchKey.reset();
Wait for the watch key to be signaled for the next set of events - (4a).
2.5. Close the watch service.
watchService.close();
NOTE:
- The example's code is for Windows operating system.
- The code is for monitoring a directory without any sub-directories; to monitor a file tree - use the
Files.walkFileTree()
static method along with the watch service.
3. The Example's Output
The example application is run from Windows OS command prompt.
- Step 1: Start the example application.
- Step 2: Note the file change notification action output.
Step1: Start the example application.
osprompt> java WatchServiceExample1
The console output:
Watch service example 1:
Registered dir: D:\JavaWatchService\testdir1
Watch key (valid): true
Waiting for watch key to be signaled...
Notes from the console output:
- The example application is started.
- The path of the directory being monitored by the watch service.
- The watch key is generated and is valid.
- The application waits for the watch key to be signaled for the monitored events on the watch service's registered directory.
Step 2: Note the file change notification action output.
From a Windows File Manager application, navigate to the directory being monitored; in the example, it is the D:\JavaWatchService\testdir1
. Perform file actions like, add, modify, rename, copy and delete on any file(s).
Here are some actions and the related results in the console output.
Action 1: Create a file.
Right-click > New > Notepad Document: This action creates a Notepad document file 'New Text Document.txt' in the watched directory 'testdir1'.
The console output:Process the pending events for the watch key: 1
Path event kind: ENTRY_CREATE
File: New Text Document.txt
Watch key reset.
Waiting for watch key to be signaled...
Note from the console output:
- The number of events for the watch key: 1
- The event kind: ENTRY_CREATE
- The file associated with the action: New Text Document.txt
- After all the pending events are processed for the watch key, the watch key is reset.
- The application waits for the next set of action events.
Action 2: Create a file (differently than that of the Action 1).
Open a document application (like MS Word or Notepad) > Open a new document file > Save the file in the watched directory 'testdir1'.
The console output:Process the pending events for the watch key: 2
Path event kind: ENTRY_CREATE
File: test1.txt
Path event kind: ENTRY_DELETE
File: test1.txt
Watch key reset.
Waiting for watch key to be signaled...
Process the pending events for the watch key: 1
Path event kind: ENTRY_CREATE
File: test1.txt
Watch key reset.
Waiting for watch key to be signaled...
Process the pending events for the watch key: 1
Path event kind: ENTRY_MODIFY
File: test1.txt
Watch key reset.
Waiting for watch key to be signaled...
Note from the console output - there are three watch keys and multiple events for each one.
Action 3: Rename a file.
Rename a file in the watched directory; for example 'test1.txt' is renamed to 'test1renamed.txt'.
The console output:Process the pending events for the key: 3
Path event kind: ENTRY_DELETE
File: test1.txt
Path event kind: ENTRY_CREATE
File: test1renamed.txt
Path event kind: ENTRY_MODIFY
File: test1renamed.txt
Watch key reset.
Waiting for watch key to be signaled...
Note from the console output - there are three events; one for the file before renaming it, and two for the renamed file.
Other File Actions:
Copy a file, delete a file and modify (open an existing document file in an editor, change some text and save) a file.
4. File Actions and Events
This shows various file change actions and the respective resulting event(s). Note that these are from the output of the example.
- File actions from Windows.
- File actions from a Java program.
4.1. File Actions from Windows
File Actions | Events | ||
---|---|---|---|
Create a file from Windows file manager application's menu: File > New > (Notepad) Document | Create | ||
Create new file from a Notepad application; and save the file. | Create | Modify | Delete |
Rename a file. | Create | Modify | Delete |
Update an existing file - edit and save an existing text file using Notepad application. | Modify | ||
Delete a file. | Delete | ||
Copy a file; either drag and drop, or copy and paste. In this case the destination file does not exist. | Create | Modify | |
Copy and replace a file. In this case the source and destination file names are same. | Modify |
4.2. File Actions from a Java Program
NOTE: The results are based on a Java program that uses Java 7 file NIO 2 API.
File Actions | Events | ||
---|---|---|---|
Create a new file. | Create | ||
Update an existing file. | Modify | ||
Rename a file. | Create | Modify | Delete |
Delete a file. | Delete | ||
Copy a file (source and target files are different). | Create | Modify | |
Copy and replace a file. | Create | Modify | Delete |
5. Notes on usage of Watch Service in Applications
Some applications using Watch Service:
- An application tracks its configuration changes in a file and this configuration file is in a directory that is monitored. As the configuration properties are changed and the file is modified while the application is running, a process (or function) monitors the directory of file changes, and applies the configuration changes to the application. The monitoring process receives a MODIFY event.
- A web server watches a web application deploy directory, waiting for an application deployment archive (.war) file to be dropped into the directory. A server process watches the deploy directory for CREATE or MODIFY events.
- An application watches a directory for a CREATE event from a FTP file upload.
- In a surveillance system (with software and a motion detection video camera) a detected motion creates a video file with a timestamp, in a watched directory. The file creation action generates a CREATE event and is processed by the software, to trigger an alert.
- In a print application, a print tray receives documents and deletes them after they are printed, in queue. A process (that displays the print queue details) monitors the print document's CREATE and DELETE events.
6. WatchServiceExample1.java
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.FileSystems;
import java.nio.file.WatchService;
import java.nio.file.WatchKey;
import java.nio.file.WatchEvent;
import static java.nio.file.StandardWatchEventKinds.*;
import java.io.IOException;
import java.util.List;
public class WatchServiceExample1 {
private static final String watchedDir = "D:\\JavaWatchService\\testdir1";
public static void main(String [] args)
throws IOException {
new WatchServiceExample1().doProcess();
}
private void doProcess()
throws IOException {
// (1) Create a new watch service
WatchService watchService = FileSystems.getDefault().newWatchService();
System.out.println("Watch service example 1:");
// (2) Get the directory to be monitored
Path dir = Paths.get(watchedDir);
// (3) Register the directory to be monitored with the watch service
WatchKey watchKey = dir.register(watchService,
ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
System.out.println("Registered dir: " + dir.toString());
System.out.println(" Watch key (valid): " + watchKey.isValid());
// (4) Get and process the events that occur
INFINITE_WHILE_LOOP:
while(true) {
// (4a) Wait for the watch key to be signaled of events
try {
System.out.println("Waiting for watch key to be signaled...");
watchService.take();
}
catch (InterruptedException ex) {
ex.printStackTrace();
break INFINITE_WHILE_LOOP;
}
// (4b) Get and process the events for the watch key
List<WatchEvent<?>> eventList = watchKey.pollEvents();
System.out.println("Process the pending events for the watch key: " +
eventList.size());
EVENT_FOR_LOOP:
for(WatchEvent<?> genericEvent: eventList) {
// Retrieve and process the event kind
if (genericEvent.kind() == OVERFLOW) {
System.out.println("Overflow event");
continue EVENT_FOR_LOOP; // next event
}
// else, genericEvent.kind() is WatchEvent.Kind<Path>
// values: ENTRY_CREATE...
System.out.println("Path event kind: " + genericEvent.kind());
// Retrieve the file name associated with the event
Path filePath = (Path) genericEvent.context();
System.out.println(" File: " + filePath.toString());
} // end EVENT_FOR_LOOP (for a watch key)
// (4c) Reset the watch key
boolean validKey = watchKey.reset();
System.out.println("Watch key reset.");
if (! validKey) {
System.out.println("Invalid watch key, close the watch service");
break INFINITE_WHILE_LOOP;
}
} // end, INFINITE_WHILE_LOOP
// (5) Close the watch service
watchService.close();
System.out.println("Watch service closed.");
} // doProcess()
} // WatchServiceExample1
7. Download
Download source code here: WatchServiceExample.zip
8. References
Link to Java SE 7 API's java.nio.file (NIO 2): http://docs.oracle.com/javase/7/docs/api/java/nio/file/package-summary.html
Return to top