HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Java 8 / Java WatchService API Tutorial

Java WatchService API Tutorial

In this example, we will learn to watch a directory along with all sub-directories and files inside it, using java 8 WatchService API.

How to register Java 8 WatchService

To Register WatchService, get the directory path and use path.register() method.

Path path = Paths.get(".");
WatchService watchService =  path.getFileSystem().newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

Watching for change events

To get the changes occured on directory and files inside it, use watchKey.pollEvents() method which return the collection of all change events in form of stream.

WatchKey watchKey = null;
while (true) {
	watchKey = watchService.poll(10, TimeUnit.MINUTES);
	if(watchKey != null) {
		watchKey.pollEvents().stream().forEach(event -> System.out.println(event.context()));
	}
	watchKey.reset();
}

The key remains valid until:

  • It is cancelled, explicitly, by invoking its cancel method, or
  • Cancelled implicitly, because the object is no longer accessible, or
  • By closing the watch service.

If you are reusing the same key to get change events multiple times inside a loop, then don’t forget to call watchKey.reset() method which set the key in ready state again.

Please note that several things such as how events are detected, their timeliness, and whether their ordering is preserved are highly dependent of underlying operating system. Some changes may result in single entry in one OS, while similar changes may result into multiple events in another OS.

Watch Directory, Sub-directories and Files for Changes Example

In this example, we will see an example of watching a directory with all sub-directories and files inside it. We will maintain a map of watch keys and directories Map<WatchKey, Path> keys to correctly identify which directory has been modified.

Below method will register a single directory to watcher and then store the directory and key inside a map.

private void registerDirectory(Path dir) throws IOException 
{
	WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
	keys.put(key, dir);
}

We will call this method recursively while walking down a directory structure and calling this for each directory we encounter.

private void walkAndRegisterDirectories(final Path start) throws IOException {
	// register directory and sub-directories
	Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
		@Override
		public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
			registerDirectory(dir);
			return FileVisitResult.CONTINUE;
		}
	});
}

Please note that at any time a new directory is created, we will register it with watchservice and a new key will be added to map.

WatchEvent.Kind kind = event.kind();
if (kind == ENTRY_CREATE) {
	try {
		if (Files.isDirectory(child)) {
			walkAndRegisterDirectories(child);
		}
	} catch (IOException x) {
		// do something useful
	}
}

Putting all above together along with logic to process the events, complete example look like this:

package com.howtodoinjava.examples;

import static java.nio.file.StandardWatchEventKinds.*;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

public class Java8WatchServiceExample {

	private final WatchService watcher;
	private final Map<WatchKey, Path> keys;

	/**
	 * Creates a WatchService and registers the given directory
	 */
	Java8WatchServiceExample(Path dir) throws IOException {
		this.watcher = FileSystems.getDefault().newWatchService();
		this.keys = new HashMap<WatchKey, Path>();

		walkAndRegisterDirectories(dir);
	}

	/**
	 * Register the given directory with the WatchService; This function will be called by FileVisitor
	 */
	private void registerDirectory(Path dir) throws IOException 
	{
		WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
		keys.put(key, dir);
	}

	/**
	 * Register the given directory, and all its sub-directories, with the WatchService.
	 */
	private void walkAndRegisterDirectories(final Path start) throws IOException {
		// register directory and sub-directories
		Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
			@Override
			public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
				registerDirectory(dir);
				return FileVisitResult.CONTINUE;
			}
		});
	}

	/**
	 * 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()) {
				@SuppressWarnings("rawtypes")
				WatchEvent.Kind kind = event.kind();

				// Context for directory entry event is the file name of entry
				@SuppressWarnings("unchecked")
				Path name = ((WatchEvent<Path>)event).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 (kind == ENTRY_CREATE) {
					try {
						if (Files.isDirectory(child)) {
							walkAndRegisterDirectories(child);
						}
					} catch (IOException x) {
						// do something useful
					}
				}
			}

			// 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;
				}
			}
		}
	}

	public static void main(String[] args) throws IOException {
		Path dir = Paths.get("c:/temp");
		new Java8WatchServiceExample(dir).processEvents();
	}
}

After running this program, and making changes in files and directories in given input, you will notice the captured events in console.

Output:

ENTRY_CREATE: c:\temp\New folder
ENTRY_DELETE: c:\temp\New folder
ENTRY_CREATE: c:\temp\data
ENTRY_CREATE: c:\temp\data\New Text Document.txt
ENTRY_MODIFY: c:\temp\data
ENTRY_DELETE: c:\temp\data\New Text Document.txt
ENTRY_CREATE: c:\temp\data\tempFile.txt
ENTRY_MODIFY: c:\temp\data
ENTRY_MODIFY: c:\temp\data\tempFile.txt
ENTRY_MODIFY: c:\temp\data\tempFile.txt
ENTRY_MODIFY: c:\temp\data\tempFile.txt

That’s all for this simple example of using Java 8 WatchService API to watch for file changes and handling them.

Happy Learning !!

Resources:

WatchService Java Doc
Walking the File Tree
Java 8 Paths
Lambda Expression

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.
TwitterFacebookLinkedInRedditPocket

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. Rejin Chandran

    March 18, 2020

    WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);

    is missing in that

  2. Douglas Silva Ribeiro

    January 7, 2018

    Dude, this post saved me. Thank you for sharing this content.

  3. Dmitry Trifonov

    December 1, 2017

    These funny examples always far from production quality:
    1. Why do you need all code in same class? Did you heard about object oriented design principles?
    2. Who will close WatchService? Btw WatchService implements Closeable interface and can be used in try..catch
    3. As soon as you will call watchService.poll() WatchKey will stop receiving events (because it is removed from WatchService) until you call WatchKey.reset(). So, you probably will loose all events that will occur between these two calls.
    4. Tell about limitations of WatchService.

    • Lokesh Gupta

      December 2, 2017

      Thanks for sharing constructive feedback. Further, I didn’t write production class code because it shift the focus from main concept, even slightly.
      1) Yes.
      2) Here discussed usecase didn’t demand to close service. If somebody want then it can be done in finalize() method.
      3) It’s good observation. Your suggestion, please??
      4) I will add them. But probably biggest limitation you covered in in your 3rd comment.

  4. Pankaj Tirpude

    May 16, 2017

    Hi Lokesh,

    What if any file is come to watched directory having big size then, Watch Service will not wait to complete the transfer of this file?
    How to solved this?

    • Maria Kamburova

      November 25, 2017

      Hi Pankaj,

      Did you solve this and if so, how?

      Regards,
      Maria

Comments are closed on this article!

Search Tutorials

Java 8 Tutorial

  • Java 8 Features
  • Java 8 forEach
  • Java 8 Stream
  • Java 8 Boxed Stream
  • Java 8 Lambda Expression
  • Java 8 Functional Interface
  • Java 8 Method Reference
  • Java 8 Default Method
  • Java 8 Optional
  • Java 8 Predicate
  • Java 8 Regex as Predicate
  • Java 8 Date Time
  • Java 8 Iterate Directory
  • Java 8 Read File
  • Java 8 Write to File
  • Java 8 WatchService
  • Java 8 String to Date
  • Java 8 Difference Between Dates
  • Java 8 Join Array
  • Java 8 Join String
  • Java 8 Exact Arithmetic
  • Java 8 Comparator
  • Java 8 Base64
  • Java 8 SecureRandom
  • Internal vs External Iteration

Java Tutorial

  • Java Introduction
  • Java Keywords
  • Java Flow Control
  • Java OOP
  • Java Inner Class
  • Java String
  • Java Enum
  • Java Collections
  • Java ArrayList
  • Java HashMap
  • Java Array
  • Java Sort
  • Java Clone
  • Java Date Time
  • Java Concurrency
  • Java Generics
  • Java Serialization
  • Java Input Output
  • Java New I/O
  • Java Exceptions
  • Java Annotations
  • Java Reflection
  • Java Garbage collection
  • Java JDBC
  • Java Security
  • Java Regex
  • Java Servlets
  • Java XML
  • Java Puzzles
  • Java Examples
  • Java Libraries
  • Java Resources
  • Java 14
  • Java 12
  • Java 11
  • Java 10
  • Java 9
  • Java 8
  • Java 7

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Sealed Classes and Interfaces