Learning The "J"

Home » JAVA Learning » JAVA Core » Directory Watch » Watching a Directory for Changes

Watching a Directory for Changes

JDK7’s java.nio.file package has a WatchService to support file change notification. You can use it to monitor a directory for changes.

You can also try jpathwatch (http://jpathwatch.wordpress.com/), which is an implementation of the WatchService interface and uses native OS functions, instead of polling.

The code below shows how you would use the Watch Service API. First, you have to create a WatchService for the file system and then register the directory you want to monitor with it. You have to specify which events (create, modify or delete) you are interested in receiving. Then start an infinite loop to wait for events. When an event occurs, a WatchKey is placed into the watch service’s queue and you have to call take to retrieve it. You can then query the key for events and print them out.

/*
  Watch the specified directory
  @param dirname the directory to watch
  @throws IOException
  @throws InterruptedException
 */
public static void watchDir(String dir)
    throws IOException, InterruptedException{
 
  //create the watchService
  final WatchService watchService = FileSystems.getDefault().newWatchService();
 
  //register the directory with the watchService
  //for create, modify and delete events
  final Path path = Paths.get(dir);
  path.register(watchService,
            StandardWatchEventKinds.ENTRY_CREATE,
            StandardWatchEventKinds.ENTRY_MODIFY,
            StandardWatchEventKinds.ENTRY_DELETE);
 
  //start an infinite loop
  while(true){
 
    //remove the next watch key
    final WatchKey key = watchService.take();
 
    //get list of events for the watch key
    for (WatchEvent watchEvent : key.pollEvents()) {
 
      //get the filename for the event
      final WatchEvent ev = (WatchEvent)watchEvent;
      final Path filename = ev.context();
 
      //get the kind of event (create, modify, delete)
      final Kind kind = watchEvent.kind();
 
      //print it out
      System.out.println(kind + ": " + filename);
    }
 
    //reset the key
    boolean valid = key.reset();
 
    //exit loop if the key is not valid
    //e.g. if the directory was deleted
      if (!valid) {
          break;
      }
  }
}

Here is a full working code

import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;
 
/**
 * Example to watch a directory (or tree) for changes to files.
 */
 
public class WatchDir {
 
    private final WatchService watcher;
    private final Map keys;
    private final boolean recursive;
    private boolean trace = false;
 
    @SuppressWarnings("unchecked")
    static  WatchEvent cast(WatchEvent event) {
        return (WatchEvent)event;
    }
 
    /**
     * Register the given directory with the WatchService
     */
    private void register(Path dir) throws IOException {
        WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
        if (trace) {
            Path prev = keys.get(key);
            if (prev == null) {
                System.out.format("register: %s\n", dir);
            } else {
                if (!dir.equals(prev)) {
                    System.out.format("update: %s -> %s\n", prev, dir);
                }
            }
        }
        keys.put(key, dir);
    }
 
    /**
     * Register the given directory, and all its sub-directories, with the
     * WatchService.
     */
    private void registerAll(final Path start) throws IOException {
        // register directory and sub-directories
        Files.walkFileTree(start, new SimpleFileVisitor() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException
            {
                register(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }
 
    /**
     * Creates a WatchService and registers the given directory
     */
    WatchDir(Path dir, boolean recursive) throws IOException {
        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap();
        this.recursive = recursive;
 
        if (recursive) {
            System.out.format("Scanning %s ...\n", dir);
            registerAll(dir);
            System.out.println("Done.");
        } else {
            register(dir);
        }
 
        // enable trace after initial registration
        this.trace = true;
    }
 
    /**
     * Process all events for keys queued to the watcher
     */
    void processEvents() {
        for (;;) {
 
            // wait for key to be signalled
            WatchKey key;
            try {
                key = watcher.take();
            } catch (InterruptedException x) {
                return;
            }
 
            Path dir = keys.get(key);
            if (dir == null) {
                System.err.println("WatchKey not recognized!!");
                continue;
            }
 
            for (WatchEvent event: key.pollEvents()) {
                WatchEvent.Kind kind = event.kind();
 
                // TBD - provide example of how OVERFLOW event is handled
                if (kind == OVERFLOW) {
                    continue;
                }
 
                // Context for directory entry event is the file name of entry
                WatchEvent ev = cast(event);
                Path name = ev.context();
                Path child = dir.resolve(name);
 
                // print out event
                System.out.format("%s: %s\n", event.kind().name(), child);
 
                // if directory is created, and watching recursively, then
                // register it and its sub-directories
                if (recursive && (kind == ENTRY_CREATE)) {
                    try {
                        if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                            registerAll(child);
                        }
                    } catch (IOException x) {
                        // ignore to keep sample readbale
                    }
                }
            }
 
            // reset key and remove from set if directory no longer accessible
            boolean valid = key.reset();
            if (!valid) {
                keys.remove(key);
 
                // all directories are inaccessible
                if (keys.isEmpty()) {
                    break;
                }
            }
        }
    } 
    static void usage() {
        System.err.println("usage: java WatchDir [-r] dir");
        System.exit(-1);
    } 
    public static void main(String[] args) throws IOException {
        // parse arguments
        if (args.length == 0 || args.length > 2)
            usage();
        boolean recursive = false;
        int dirArg = 0;
        if (args[0].equals("-r")) {
            if (args.length < 2)
                usage();
            recursive = true;
            dirArg++;
        }
        // register directory and process its events
        Path dir = Paths.get(args[dirArg]);
        new WatchDir(dir, recursive).processEvents();
    }
}
Advertisements

2 Comments

  1. Dan says:

    Hi I can’t get the code running in my computer, where do I give my directory the directory I wanna monitor as argument

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Start here

%d bloggers like this: