Monitorear cambios en archivos de una carpeta

Cuando necesitemos desarrollar una aplicación que este pendiente de los cambios que ocurren en los archivos contenidos dentro de una carpeta como: modificación, eliminación o creación, la solución es utilizar la API Watch Service que nos permitirá recibir notificaciones de los cambios ocurridos dentro del directorio indicado.

Para monitorear las modificaciones en una carpeta haremos los siguientes pasos:

  1. Crear un objeto WatchService que será el encargado de observar los cambios en una o varias carpetas.
  2. Registrar la carpeta y los cambios que deseamos monitorear, estos cambios están definidos en la clase StandardWatchEventKinds.
  3. Crear un bucle en donde verificaremos si existe un evento en la cola.
  4. Obtener el objeto WatchKey que nos brinda información sobre el evento ocurrido.
  5. Resetear el objeto WatchKey y continuar el bucle.
  6. Para terminar el monitoreo usaremos el método close().

El código de ejemplo:

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardWatchEventKinds.*;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

public class Watcher {

    public static void main(String[] args) {
        try (WatchService ws = FileSystems.getDefault().newWatchService()) {
            // carpeta que deseamos monitorear    
            Path dirToWatch = Paths.get("C:\\developer\\temp");

            // eventos que deseamos que nos envien notificaciones
            dirToWatch.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
            System.out.println("Watching " + dirToWatch + " for events.");
            
            while (true) {
                // obtener el key
                WatchKey key = ws.take();
                
                // procesar los eventos ocurridos
                for (WatchEvent<?> event : key.pollEvents()) {
                    Kind<?> eventKind = event.kind();
                    if (eventKind == OVERFLOW) {
                        System.out.println("Event overflow occurred");
                        continue;
                    }
                    
                    // obtener informacion del evento ocurrido
                    WatchEvent<Path> currEvent = (WatchEvent<Path>) event;
                    Path dirEntry = currEvent.context();

                    System.out.println(eventKind + " occurred on " + dirEntry);
                }
                
                // resetear el key
                boolean isKeyValid = key.reset();
                if (!isKeyValid) {
                    break;
                }
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Programación con la API Watch Service

El objeto WatchService es creado usando la clase FileSystems:

WatchService ws = FileSystems.getDefault().newWatchService()

Luego obtenemos el Path que representa la carpeta que deseamos monitorear y registramos los eventos que deseamos recibir, ellos son: ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE, los cuales indican los eventos de creación, modificación y eliminación de un archivo que se encuentre dentro de la carpeta indicada.

// carpeta que deseamos monitorear    
Path dirToWatch = Paths.get("C:\\developer\\temp");

// eventos que deseamos que nos envien notificaciones
dirToWatch.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);

Creamos el bucle que nos permitirá obtener y procesar todos los eventos que se encuentren en la cola.

for (;;) {
    // obtener el key
    WatchKey key = watcher.take();

    // procesar los eventos ocurridos 
    for (WatchEvent<?> event: key.pollEvents()) {
        :
    }

    // resetear el key
    boolean valid = key.reset();
    if (!valid) {
        break;
    }
}

Finalmente procesamos cado uno de los eventos, verificamos si el evento es OVERFLOW esto indica si dicho evento a sido descartado o se ha perdido, en tal caso continuamos, en caso contrario podemos obtener el evento ocurrido e información del mismo, en nuestro ejemplo mostramos la carpeta que ha producido el mencionado evento.

for (WatchEvent<?> event : key.pollEvents()) {
    Kind<?> eventKind = event.kind();
    if (eventKind == OVERFLOW) {
        System.out.println("Event overflow occurred");
        continue;
    }

    // obtener informacion del evento ocurrido
    WatchEvent<Path> currEvent = (WatchEvent<Path>) event;
    Path dirEntry = currEvent.context();

    System.out.println(eventKind + " occurred on " + dirEntry);
}

Si ejecutamos nuestra aplicación y hacemos los respectivos cambios en la carpeta indicada obtendremos la siguiente salida:

Monitorear cambios de una carpeta usando la API Wath Service

Como podemos ver si, agregamos, eliminamos o editamos un archivo en la carpeta establecida nuestra aplicación recibirá las notificaciones correspondientes.

Comentarios

  1. No funciona cuando la carpeta es Montada (Remota) ...
    hay que hacer algun ajuste???.

    gracias

    ResponderEliminar
  2. Hola, este ejemplo es mas optimo aplicarlo con Threads o asi como lo muestra en el ejemplo??

    ResponderEliminar
    Respuestas
    1. Depende del uso que tengas planeado, igual se puede aplicar de uno u otra forma.

      Eliminar

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Histogramas OpenCV Python

Python Binance API