mai
2011
Filesystem notifications with Java 7
A developer sought yesterday some advice about the best way to implement the following feature in his application : how to react, as quickly as possible, to the creation of a special "lock file" in a well-known directory.
His current implementation uses a polling thread calling the File.exists()
method every few hundreds ms, which is a best-effort tradeoff between notification speed and unnecessary CPU burning.
As of Java 7, there is a better way to achieve this.
The java.nio.file
package provides a WatchService
that plugs directly into the underlying OS's file notification system, allowing the application to be asychronously notified of filesystem-related events of certain types (file creation, modification, deletion, etc.).
This WatchService
works alot like the dreaded NIO channel Selector
, but is fortunately simpler : first declare which events you are interested in, then loop on a blocking method to wait for some event to occur, process it as required, rince and repeat.
Here is what I quickly coded as a proof-of-concept.
public class LockFileDetector { public static void main(String[] args) throws IOException { if (args.length < 1) { System.out.println("Usage : LockFileDetector <file>"); System.exit(0); } new LockFileDetector().detectLockFile(args[0]); } public void detectLockFile(String lockFilePath) throws IOException { // Plug into the OS's filesystem notification service WatchService watcher = FileSystems.getDefault().newWatchService(); // Get Paths for the not-yet-existing lock file and its parent directory Path lockFile = Paths.get(lockFilePath); Path lockFileDir = lockFile.getParent(); // Ask to be notified if a file is created in the directory lockFileDir.register(watcher, ENTRY_CREATE); // While the lock file does not exist... WatchKey watchKey; _watchLoop: while (!Thread.currentThread().isInterrupted()) { // Wait for some event to occur in the directory try { watchKey = watcher.take(); if (!watchKey.isValid()) { continue; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } // Cycle through the events final List<WatchEvent<?>> watchEvents = watchKey.pollEvents(); for (WatchEvent<?> event : watchEvents) { // Ensure it is a creation event if (event.kind().equals(ENTRY_CREATE)) { // Compute the new file's full path Path createdFileRelativePath = (Path) event.context(); Path createdFileAbsolultePath = lockFileDir.resolve(createdFileRelativePath); // Is it our lock file ? if (createdFileAbsolultePath.equals(lockFile)) { System.out.println("Lock file detected !"); } } } watchKey.reset(); } watcher.close(); } }
This code works pretty well on my Linux-powered laptop, there is no noticeable delay between the file creation and the notification.
If you want to test it on your own platform, run the code with the lock file path as an argument (see below), then create the expected file. The notification should appear in the console.
java LockFileDetector /home/olivier/Desktop/lock.lck
Hope that helps !
Commentaires
Thanks Olivier for the POC :-)
Is there a way to be notified when a file creation is finished ? I mean when the file has finished to be written on the file system.
En cherchant des exemples, je suis tombé sur <a href="http://jpathwatch.wordpress.com">jpathwatch</a> qui lui est compatible Java 5.
Sachant que jpathwatch est compatible au niveau interface et plus complet (support Mac, plus de modifications).