Watching a Directory for Changes

Watch Service Overview

The WatchService API is fairly low level, allowing you to customise it. You can use it as is, or you can choose to create a high-level API on top of this mechanism so that it is suited to your particular needs. The WatchService API lets you receive notification events upon changes to the subject (directory or file).

The steps involved in implementing the API are:

  • Create a WatchService. This service consists of a queue to holdWatchKeys
  • Register the directory/file you wish to monitor with this WatchService
  • While registering, specify the types of events you wish to receive (create, modify or delete events)
  • You have to start an infinite loop to listen to events
  • When an event occurs, a WatchKey is placed into the queue
  • Consume the WatchKey and invoke queries on it

Let’s follow this via an example. We create a DirWatcher Java program whose responsibility is to watch a particular directory (Downloads in my case). The steps are provided below:

1. Creating an WatchService object:

WatchService  watchService = FileSystems.getDefault().newWatchService();

2. Obtain a path reference to your watchable directory. I suggest you parameterize this directory so you don’t hard code the file name.

path = Paths.get(System.getProperty("user.home") + "/Downloads");

3. The next step is to register the directory with the WatchService for all types of events:

path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

When registering an object with the watch service, you specify the types of events that you want to monitor. The supported StandardWatchEventKinds event types follow:

  • ENTRY_CREATE – A directory entry is created.
  • ENTRY_DELETE – A directory entry is deleted.
  • ENTRY_MODIFY – A directory entry is modified.
  • OVERFLOW – Indicates those events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it.

4. Initiate the infinite loop and start taking the events:

while(true) {
    try {
        key = watchService.take();
.
.
.

    } catch (InterruptedException e) {
        System.out.println("InterruptedException: "+e.getMessage());
    }

 

5. Run through the events on the key:

for (WatchEvent<?> event : key.pollEvents()) {
      WatchEvent.Kind<?> kind = event.kind();
      System.out.println("Event on " + event.context().toString() + " is " + kind);
 }

For example, if you modify or delete the Download directory, you would see statement as shown below on the console respectively:

Event on newFile.txt is ENTRY_CREATE
Event on newFile.txt is ENTRY_MODIFY

 

Example source code:

import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

/**
 * Created by marom on 28/09/16.
 */
public class DirWatcher {


        private Path path = null;
        private WatchService watchService = null;

        protected void init() {
            path = Paths.get(System.getProperty("user.home") + "/Downloads");
            try {
                watchService = FileSystems.getDefault().newWatchService();
                path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            } catch (IOException e) {
                System.out.println("IOException"+ e.getMessage());
            }
        }


        protected void doRounds() {
            WatchKey key = null;
            while(true) {
                try {
                    key = watchService.take();
                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        System.out.println("Event on " + event.context().toString() + " is " + kind);
                    }
                } catch (InterruptedException e) {
                    System.out.println("InterruptedException: "+e.getMessage());
                }
                boolean reset = key.reset();
                if(!reset)
                    break;
            }
        }
}

 

public class Main {

    public static void main(String[] args) {

        DirWatcher watcher = new DirWatcher();
        watcher.init();
        watcher.doRounds();
    }
}

 

Leave a Reply