In this article I show how to watch files and directories for additions/changes/deletions using the new file system support in Java 7. Finally, after years of native solutions, it is now possible to listen for file changes without resorting to OS specific solutions.
In the code below, first we use the new file system support class Paths
to get a Path
object that represents our particular directory. We then create a watching service, that we will use to listen for changes and finally we register our path (directory) with the watcher for files that are created. You can watch for other events, take a look at StandardWatchEventKinds
Once this class is run, any new files created in the directory will result in the log line in the run method of MyWatchQueueReader being executed.
package com.thecoderscorner.niostuff;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
public class NioFileSupport {
/** change this as appropriate for your file system structure. */
public static final String DIRECTORY_TO_WATCH = "c:/Dev/temp/";
public static void main(String[] args) throws Exception {
// get the directory we want to watch, using the Paths singleton class
Path toWatch = Paths.get(DIRECTORY_TO_WATCH);
if(toWatch == null) {
throw new UnsupportedOperationException("Directory not found");
}
// make a new watch service that we can register interest in
// directories and files with.
WatchService myWatcher = toWatch.getFileSystem().newWatchService();
// start the file watcher thread below
MyWatchQueueReader fileWatcher = new MyWatchQueueReader(myWatcher);
Thread th = new Thread(fileWatcher, "FileWatcher");
th.start();
// register a file
toWatch.register(myWatcher, ENTRY_CREATE, ENTRY_MODIFY);
th.join();
}
/**
* This Runnable is used to constantly attempt to take from the watch
* queue, and will receive all events that are registered with the
* fileWatcher it is associated. In this sample for simplicity we
* just output the kind of event and name of the file affected to
* standard out.
*/
private static class MyWatchQueueReader implements Runnable {
/** the watchService that is passed in from above */
private WatchService myWatcher;
public MyWatchQueueReader(WatchService myWatcher) {
this.myWatcher = myWatcher;
}
/**
* In order to implement a file watcher, we loop forever
* ensuring requesting to take the next item from the file
* watchers queue.
*/
@Override
public void run() {
try {
// get the first event before looping
WatchKey key = myWatcher.take();
while(key != null) {
// we have a polled event, now we traverse it and
// receive all the states from it
for (WatchEvent event : key.pollEvents()) {
System.out.printf("Received %s event for file: %s\n",
event.kind(), event.context() );
}
key.reset();
key = myWatcher.take();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Stopping thread");
}
}
}
Hopefully this has given you a feel for how to implement this Java 7 feature. It's worth bearing in mind that this requires users to have Java 7 installed. Here is the example output from the above when I created a new file from windows explorer
Received ENTRY_MODIFY event for file: 123.txt Received ENTRY_MODIFY event for file: 1233.txt Received ENTRY_MODIFY event for file: 1233.txt Received ENTRY_CREATE event for file: 123t.txt Received ENTRY_MODIFY event for file: 123t.txt
This is probably first of a new series of Java articles on my blog, someone managed to finally drag me away from building speakers and amplifiers for a while! I'll write a few more following on from this on NIO