Cómo detectar cambios en un directorio con Java con un WatchService

Antonio J. Galisteo

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!

Publicado el 18-08-2021

Donar

Si te ha sido de ayuda y quieres hacer una donación te lo agradeceremos :)

Compartelo!


Deja un comentario

Comentanos

*

Ir arriba de la pagina