WatchService: supervisión de cambios en archivos
Registre un WatchService para detectar en tiempo real eventos de creación, modificación y eliminación de archivos.
WatchService: supervisión de cambios en archivos es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
¿Qué es WatchService?
WatchService supervisa un directorio en busca de eventos del sistema de archivos: creación, modificación y eliminación. Utiliza notificaciones a nivel del sistema operativo (inotify en Linux, FSEvents en macOS), lo que resulta mucho más eficiente que el sondeo.
import java.nio.file.*;
WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Path.of("/home/user/watched");
dir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE
);
System.out.println("Watching: " + dir);Sondeo de eventos
Llame a watcher.take() para bloquear la ejecución hasta que ocurra un evento y, después, procese los eventos:
while (true) {
WatchKey key;
try {
key = watcher.take(); // blocks until events arrive
} catch (InterruptedException e) {
break;
}
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
Path changed = ((WatchEvent<Path>) event).context();
System.out.println(kind.name() + ": " + changed);
}
key.reset(); // must reset to receive further events
}Sondeo sin bloqueo
Use watcher.poll() para realizar comprobaciones sin bloqueo o poll(timeout, unit) para esperar durante un tiempo determinado:
// Non-blocking — returns null if no events
WatchKey key = watcher.poll();
if (key != null) {
// process events
key.reset();
}
// Wait up to 5 seconds:
WatchKey key2 = watcher.poll(5, java.util.concurrent.TimeUnit.SECONDS);
if (key2 != null) {
// process events
key2.reset();
}Evento OVERFLOW
Si los eventos se acumulan más rápido de lo que la aplicación puede procesarlos, un evento OVERFLOW indica que se han perdido algunos eventos. Manéjelo correctamente:
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == StandardWatchEventKinds.OVERFLOW) {
System.out.println("OVERFLOW: some events missed, rescanning directory");
// rescan dir to find current state
continue;
}
// process normal events
}Ejemplo completo en funcionamiento
Un monitor de archivos completo que se ejecuta en un hilo en segundo plano:
class FileWatcher implements Runnable {
private final WatchService watcher;
FileWatcher(Path dir) throws IOException {
watcher = FileSystems.getDefault().newWatchService();
dir.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
WatchKey key = watcher.take();
for (WatchEvent<?> e : key.pollEvents())
System.out.println(e.kind() + ": " + e.context());
key.reset();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}Supervisión de varios directorios
Registre varios directorios con el mismo WatchService. Use el WatchKey devuelto para identificar de qué directorio procede el evento:
Map<WatchKey, Path> keyMap = new HashMap<>();
for (Path dir : List.of(Path.of("/logs"), Path.of("/config"))) {
WatchKey key = dir.register(watcher,
StandardWatchEventKinds.ENTRY_MODIFY);
keyMap.put(key, dir);
}
WatchKey key = watcher.take();
Path dir = keyMap.get(key);
System.out.println("Changed in: " + dir);Resolución de la ruta completa
context() del evento devuelve solo el nombre del archivo, no la ruta completa. Resuélvalo respecto al directorio supervisado:
WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
Path filename = pathEvent.context();
Path fullPath = watchedDir.resolve(filename);
System.out.println("Full path: " + fullPath);Supervisión recursiva de directorios
WatchService supervisa únicamente el directorio registrado, no sus subdirectorios. Para realizar una supervisión recursiva, recorra el árbol y registre cada subdirectorio:
WatchService watcher = FileSystems.getDefault().newWatchService();
Path root = Path.of("/project");
try (var stream = Files.walk(root)) {
stream.filter(Files::isDirectory)
.forEach(dir -> {
try { dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
} catch (IOException e) { throw new RuntimeException(e); }
});
}Liberación de recursos
Cierre siempre WatchService cuando termine para liberar los recursos del sistema operativo:
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
Path dir = Path.of("/tmp/watch");
dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
WatchKey key = watcher.poll(10, java.util.concurrent.TimeUnit.SECONDS);
if (key != null) {
key.pollEvents().forEach(e -> System.out.println(e.context()));
key.reset();
}
} // watcher.close() called automaticallyCaso práctico: recarga en caliente de la configuración
Use WatchService para volver a cargar la configuración cuando cambie el archivo:
class ConfigWatcher {
private volatile Map<String, String> config = new HashMap<>();
void loadConfig(Path file) throws IOException {
config = Files.readAllLines(file).stream()
.filter(l -> l.contains("="))
.collect(Collectors.toMap(
l -> l.split("=")[0].trim(),
l -> l.split("=")[1].trim(),
(a,b) -> b
));
}
// Call loadConfig again on ENTRY_MODIFY event
}Limitaciones de WatchService
Limitaciones importantes:
- Supervisa únicamente directorios, no archivos individuales
- No es recursivo de forma predeterminada: debe registrar manualmente cada subdirectorio
- En macOS: utiliza sondeo internamente, por lo que responde peor que inotify en Linux
- Puede no detectar ráfagas rápidas de cambios (OVERFLOW)
- WatchKey deja de ser válido si se elimina el directorio supervisado
Comprobación rápida
Después de procesar los eventos de un WatchKey, ¿qué debe llamar antes de que WatchService pueda entregar más eventos para esa clave?
Repaso: WatchService
Conceptos clave:
- Registre directorios para los eventos ENTRY_CREATE/MODIFY/DELETE
- take() bloquea; poll() no bloquea; use poll(timeout, unit) para esperar durante un tiempo determinado
- Llame siempre a key.reset() después de procesar los eventos
- context() devuelve únicamente el nombre del archivo: resuélvalo respecto al directorio supervisado para obtener la ruta completa
- Cierre WatchService mediante try-with-resources
- La supervisión recursiva requiere registrar cada subdirectorio
Preguntas frecuentes
¿La lección «WatchService: supervisión de cambios en archivos» es gratis?
Sí — el texto completo de «WatchService: supervisión de cambios en archivos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «WatchService: supervisión de cambios en archivos»?
Registre un WatchService para detectar en tiempo real eventos de creación, modificación y eliminación de archivos. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «WatchService: supervisión de cambios en archivos»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Path: representación de ubicaciones de archivos
- Utilidad Files: leer, escribir, copiar y mover
- Recorrido de árboles de directorios con Files.walk
- WatchService: supervisión de cambios en archivos