How to detect changes in a directory in java / How to monitor a directory using java

Monitoring directory : Meaning & Reason

Monitoring a directory or a folder means keeping a watch on that directory for events such as a new file created, a file removed or modified. A typical requirement for such monitoring would be to implement an auto refresh functionality where you show the contents of a folder. With active monitoring on a folder, you can display the accurate list of files when the directory contents are modified in the background.

How to Monitor a directory in Java

Java 7 introduced java.nio package which provides support for monitoring a directory for changes. It allows us to create a service which watches a directory for any modifications in its contents. The directory is required to be registered with a service so that the service is notified whenever the event(for which the directory was registered) occurs.

Implementation steps

Let’s go to action and write the code to monitor a directory. First, we shall outline the steps which are required for this. Our code will also follow the same sequence of steps.

  1. First step is to create a java.nio.file.WatchService object. This object can be created in 2 ways: from the default file system of the machine on which java is running(using the code FileSystems.getDefault().newWatchService()) or using the object of directory which we wish to monitor. Second approach uses the code path.getFileSystem().newWatchService() where path is an object of type java.nio.file.Path and refers to the path of directory which we are monitoring. Thus, if we are using second approach, we need to create a java.nio.file.Path object first.
    We shall use this approach in our code.
  2. Second step is to register the directory with the watch service which we created above for the events we want to detect. Events may be file creation, deletion or modification. This is done using register method which takes the watch service and event types are arguments.
  3. Creating a watch key which is an object of type java.nio.file.WatchKey. This key receives the notification when an event occurs. These events can be retrieved using pollEvents method of WatchKey. A WatchKey can be created by calling poll or take method on watcher object. Difference between poll and take methods is that poll returns null if the event is not detected at the time when this method is called while take method goes in waiting state if the event is not detected at the time when it is called.
  4. Finally, when you get the list of events, you can check for the kind of event(create, delete, modify) and take the appropriate action if this is the event you are interested in.

Now, we shall translate the above algorithm into code. Read code comments to get a better understanding of the concept.

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.UUID;

public class DirectoryWatcher {
   public static void main(String[] args) {
	// get path object pointing to the directory we wish to monitor
	Path path = Paths.get("E:\\codippa");
	try {
		// get watch service which will monitor the directory
		WatchService watcher = path.getFileSystem().newWatchService();
		// associate watch service with the directory to listen to the event
		// types
		path.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
		System.out.println("Monitoring directory for changes...");
		// listen to events
		WatchKey watchKey = watcher.take();
		// get list of events as they occur
		List<WatchEvent<?>> events = watchKey.pollEvents();
		//iterate over events
		for (WatchEvent event : events) {
			//check if the event refers to a new file created
			if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
				//print file name which is newly created
				System.out.println("Created: " + event.context().toString());
			}
		}
	} catch (IOException e) {
		e.printStackTrace();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
   }
}
All types of events which we want to listen can be provided together in the register method as
path.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);

Explanation & Output

As you can see, the above code is based on exact same steps which we outlined in the algorithm before the code snippet. The program is monitoring a folder “E:\\codippa” on the Windows filesystem. This is created as a java.nio.file.Path object using static get method of java.nio.file.Paths class. Before executing the program, the contents of the folder were as below:

When the program is executed, it keeps on listening for events on the specified folder. Following is the output of the program when a file is added to this folder as shown in the image below:

Monitoring directory for changes…
Created: Readme.txt

Note that the above program will terminate as soon as a file is created in the designated folder. If you want to listen for events forever, then surround the code starting from watcher.take() statement inside an infinite loop. Also, the above code will block till a create event occurs. So, if don’t want it to block then execute this code inside a new thread.

Let’s tweak in

  1. Only an object which is watchable can be registered with a Watch Service. This means that only an object which implements java.nio.file.Watchable interface can be registered. Since java.nio.file.Path implements this interface, it can be registered with a Watch Service.
  2. A watch key can be used by multiple threads at the same time.
  3. No matter what kind of events you have registered for listening, there are chances for an OVERFLOW event to occur. This event indicates that some events may have lost or discarded.
  4. register method also returns a watch key but we should use the watch key returned by take or poll methods to read and iterate over the events. Same has been done in the above example.
  5. Types of events that can be monitored are defined in java.nio.file.StandardWatchEventKinds class as constants. This is a final class.

Leave a Reply