Since Java 7, the java.nio.file package adds a feature: file change notification with Watch Service API – java.nio.file.WatchService
. Watch Service API allows us to register directories with the watch service, and monitor the directories and files for any changes including creation, deletion, modification etc. The post will briefly introduce the usage of Watch Service API.
Usage of Watch Service API
Step 1: create a new Watch Service
1 |
WatchService watcher = FileSystems.getDefault().newWatchService(); |
Step 2: register directories to be watched
1 2 3 4 5 |
Path mypath = Paths.get("/tmp/test"); if(mypath == null) { throw new IOException("wrong directory"); } mypath.register(watcher, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); |
When registering an object with the watch service, you specify the types of events that you want to monitor:
ENTRY_CREATE – a directory or file is created
ENTRY_DELETE – a directory or file is deleted
ENTRY_MODIFY – a directory or file is modified
OVERFLOW – the event might have been lost or discarded
Step 3: process events
- Get a queued watch key. Three methods are provided: poll, poll(long, TimeUnit), take
- Process the pending event list for the key.
- Retrieve the type of event by using the kind method.
- Retrieve the file name associated with the event.
- After the events for the key have been processed, you need to put the key back into a ready state by invoking reset.
Example code 1 (use thread)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
package net.tecbar.file; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; 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.WatchEvent.Kind; import java.nio.file.WatchKey; import java.nio.file.WatchService; public class WatchServiceDemo { protected static final Kind<?> OVERFLOW = null; public static void main(String[] args) throws IOException, InterruptedException { // make a new watch service WatchService watcher = FileSystems.getDefault().newWatchService(); // the patch to be watched Path mypath = Paths.get("/tmp/test"); if(mypath == null) { throw new IOException("wrong directory"); } // registers the file located by the path with a watch service. // invoke KeyEvent when: ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE mypath.register(watcher, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); // start the watcher thread Runnable runnable = createRunnable(watcher); final Thread consumer = new Thread(runnable); consumer.start(); } private static Runnable createRunnable(final WatchService watcher) { return new Runnable() { public void run() { try { WatchKey key = watcher.take(); while(key != null) { // traverse polled events for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); System.out.printf("Received %s WatchEvent on %s\n", kind, event.context() ); } // Reset the key -- this step is critical if you want to // receive further watch events. key.reset(); key = watcher.take(); } } catch (InterruptedException ie) { // handle your exception here ie.printStackTrace(); } } }; } } |
Example code 2 (use loop)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package net.tecbar.file; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; 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.WatchEvent.Kind; import java.nio.file.WatchKey; import java.nio.file.WatchService; public class WatchServiceDemo2 { protected static final Kind<?> OVERFLOW = null; public static void main(String[] args) throws IOException, InterruptedException { // create a new watch service WatchService watcher = FileSystems.getDefault().newWatchService(); // the patch to be watched Path mypath = Paths.get("/tmp/test"); if(mypath == null) { throw new IOException("wrong directory"); } // registers the files located by the path with a watch service. // invoke KeyEvent when: ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE mypath.register(watcher, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); while (true) { final WatchKey wk = watcher.take(); for (WatchEvent<?> event : wk.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); System.out.printf("Received %s WatchEvent on %s\n", kind, event.context() ); } // reset the key boolean valid = wk.reset(); if (!valid) { System.out.println("Key has been unregisterede"); } } } } |
Output
1 2 3 4 5 6 7 8 |
Received ENTRY_MODIFY WatchEvent on t2.txt Received ENTRY_MODIFY WatchEvent on t2.txt Received ENTRY_MODIFY WatchEvent on newspaper.xml Received ENTRY_DELETE WatchEvent on t4.txt Received ENTRY_MODIFY WatchEvent on newspaper.xml Received ENTRY_MODIFY WatchEvent on t1.txt |