I've created a WatchDirService class to simplicity the effort with NIO's WatchService. I also added the feature to watch entire classes include subdir. The process of recursively register directory with WatchService is a lightweight process and somewhat interesting me, so I include it into my class.
Usage Example:
Source code: Gist
The WatchEventAction interface:
I don't see any sensible performance problem with this API. As the example above, I register entire E:\ drive with it (79.5GB size, ~2500 file, 1100 folder) and quickly making event in a deep directory. It interact very fast. No overhead at start time.

Usage Example:
PHP:
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
/**
*
* @author NguyenHaiDang
*/
public class Test {
public static void main(String[] args) throws IOException, InterruptedException {
//monitor CREATE and DELETE event
WatchDirService watchService = new WatchDirService(true, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE);
//register a directory, can call multiple times to register multiple directories
watchService.registerDir(Paths.get("E:\\"));
//register an action when a new file/dir created
watchService.setOnCreatedAction(new WatchEventAction() {
@Override
public void doAction() {
//get the Path object of the file which make event happent
Path path = watchService.getCurrentFilePath();
//print out its absolute path
System.out.println(path.toAbsolutePath().toString());
}
});
//register an action when a new file/dir deleted
watchService.setOnDeletedAction(new WatchEventAction() {
@Override
public void doAction() {
//get the Path object of the file which make event happent
Path path = watchService.getCurrentFilePath();
//print out its absolute path
System.out.println(path.toAbsolutePath().toString());
}
});
//start it in a seperate thread
new Thread(watchService).start();
}
}
Source code: Gist
PHP:
package com.activestudy.Utility.file.watchservice;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.attribute.BasicFileAttributes;
/**
* A class based on NIO's WatchService to watch entire folder.
*
* @author NguyenHaiDang@ActiveStudy
*/
public class WatchDirService implements Runnable {
private final WatchService watchService;
private final Map<WatchKey, Path> keyPathMap = new HashMap<>();
private final WatchEvent.Kind[] eventKinds;
private Path currentFilePath;
private WatchEventAction onCreatedAction;
private WatchEventAction onModifiedAction;
private WatchEventAction onDeletedAction;
private final boolean all;
public WatchDirService(boolean all, WatchEvent.Kind... eventKinds) {
try {
this.watchService = FileSystems.getDefault().newWatchService();
} catch (IOException ex) {
throw new RuntimeException("Cannot create watch service. Reason: ", ex);
}
this.eventKinds = eventKinds;
this.all = all;
}
/**
* This blocking method continously watch given directories until an
* exception throw or it have no job to do anymore (ex: folder deleted,
* permission changed...)
*
* @throws IOException
* @throws InterruptedException
*/
private void watch() throws IOException, InterruptedException {
MAIN_LOOP:
while (true) {
final WatchKey key = watchService.take();
INNER_LOOP:
for (WatchEvent<?> watchEvent : key.pollEvents()) {
final Kind<?> kind = watchEvent.kind();
WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
Path fileName = watchEventPath.context();
Path parentDir = keyPathMap.get(key);
Path child = parentDir.resolve(fileName);
setCurrentFilePath(child);
if (kind == ENTRY_CREATE) {
if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS) && all) {
registerDir(child);
}
performAction(onCreatedAction);
continue;
}
if (kind == ENTRY_MODIFY) {
performAction(onModifiedAction);
continue;
}
if (kind == ENTRY_DELETE) {
performAction(onDeletedAction);
}
}
boolean validKey = key.reset();
if (!validKey) {
keyPathMap.remove(key);
if (keyPathMap.isEmpty()) {
watchService.close();
break MAIN_LOOP;
}
}
}
}
private void registerPath(Path path) throws IOException {
WatchKey key = path.register(watchService, eventKinds);
keyPathMap.put(key, path);
}
/**
* Register a directory to watch
*
* @param dir Path, the Path object represent the directory
* @throws IOException
*/
public void registerDir(Path dir) throws IOException {
if (Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) {
if (all) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
registerPath(dir);
return FileVisitResult.CONTINUE;
}
public FileVisitResult visitFileFailed(Path file, IOException exc)
throws IOException {
return FileVisitResult.CONTINUE;
}
});
} else registerPath(dir);
}
}
private void setCurrentFilePath(Path file) {
currentFilePath = file;
}
/**
*
* @return the Path object of the file which is making current event
*/
public Path getCurrentFilePath() {
return currentFilePath;
}
public void setOnCreatedAction(WatchEventAction onCreatedAction) {
this.onCreatedAction = onCreatedAction;
}
public void setOnModifiedAction(WatchEventAction onModifiedAction) {
this.onModifiedAction = onModifiedAction;
}
public void setOnDeletedAction(WatchEventAction onDeletedAction) {
this.onDeletedAction = onDeletedAction;
}
private void performAction(WatchEventAction ea) {
ea.doAction();
}
@Override
public void run() {
try {
watch();
} catch (IOException | InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
PHP:
/**
* Provide an action when a WatchEvent happen
* @author NguyenHaiDang
*/
public interface WatchEventAction {
void doAction();
}
I appropriate any help to improve this class design and effeciency. If forum's admins accept this, I hope it can join congdongjava's library. Thank you 
Sửa lần cuối: