Cómo detectar cambios en un directorio con Java con un WatchService
Anuncio:
En esta ocasión te quiero mostrar cómo detectar cambios en un directorio con Java. Para ellos nos vamos a apoyar en la clase WatchService para crear un servicio que esté escuchando los eventos producidos en un directorio. Podremos detectar la cración, modificación y eliminación de directorios y archivos.
En primer lugar te voy a mostrar el código de la clase y después te haré las observaciones oportunas. El código para detectar los cambios en un directorio es:
package com.myapp.files;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
/**
* Watch service for path directory
*/
public class PathWatchService {
// Watcher
private final WatchService watcher;
// Events keys
private final Map keys;
/**
* Creates a WatchService and registers the given directory
*/
public PathWatchService(Path dir) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap();
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() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerDirectory(dir);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Process all events for keys queued to the watcher
*/
public void processEvents() {
// Process all events
for (;;) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException e) {
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)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 || kind == ENTRY_MODIFY) {
try {
if (Files.isDirectory(child)) {
walkAndRegisterDirectories(child);
} else {
System.out.println("It's a file!!!");
}
} catch (IOException e) {
// do something useful
System.out.println("Error on file or directory processing...");
e.printStackTrace();
}
}
}
// 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;
}
}
}
}
}
bien, vamos ahora a explicar el código anterior. Hemos creado la clase PathWatchService cuyo constructor recibe como parámetro el path del directorio que queremos monitorizar.
El constructor crea un WatchService y registra el directorio para que se este observando.
Una vez que se está observando el directorio, tenemos un método llamado processEvents que lo que hace es procesar los eventos que se van generando. Aquí podremos ver si el evento es de creación, modificación y eliminación, además de si es un archivo o un directorio.
Ya sabes cómo detectar cambios en un directorio con Java. Puedes aprender más en nuestra sección de Java.
Espero que te haya sido de utilidad!