0Pricing
Java Academy · Leçon

WatchService : surveiller les changements de fichiers

Enregistrez un WatchService pour détecter en temps réel les événements de création, de modification et de suppression de fichiers.

WatchService : surveiller les changements de fichiers est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que WatchService ?

WatchService surveille un répertoire à la recherche d’événements du système de fichiers : création, modification et suppression. Il utilise des notifications au niveau de l’OS (inotify sous Linux, FSEvents sous macOS) — bien plus efficace que l’interrogation répétée.

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);

Interrogation des événements

Appelez watcher.take() pour bloquer jusqu’à ce qu’un événement se produise, puis traitez les événements :

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
}

Interrogation sans blocage

Utilisez watcher.poll() pour effectuer des vérifications sans blocage, ou poll(timeout, unit) pour des attentes temporisées :

// 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();
}

Événement OVERFLOW

Si les événements s’accumulent plus rapidement que l’application ne les traite, un événement OVERFLOW indique que certains événements ont été perdus. Gérez cette situation correctement :

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
}

Exemple complet fonctionnel

Un observateur de fichiers complet qui s’exécute sur un fil d’exécution en arrière-plan :

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();
            }
        }
    }
}

Surveiller plusieurs répertoires

Enregistrez plusieurs répertoires avec le même WatchService. Utilisez le WatchKey renvoyé pour identifier le répertoire d’origine de l’événement :

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);

Résoudre le chemin complet

La méthode context() de l’événement renvoie uniquement le nom du fichier, et non son chemin complet. Résolvez-le par rapport au répertoire surveillé :

WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
Path filename = pathEvent.context();
Path fullPath = watchedDir.resolve(filename);
System.out.println("Full path: " + fullPath);

Surveillance récursive des répertoires

WatchService surveille uniquement le répertoire enregistré, et non ses sous-répertoires. Pour effectuer une surveillance récursive, parcourez l’arborescence et enregistrez chaque sous-répertoire :

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); }
          });
}

Nettoyage des ressources

Fermez toujours le WatchService lorsque vous avez terminé afin de libérer les ressources de l’OS :

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 automatically

Cas pratique : rechargement à chaud de la configuration

Utilisez WatchService pour recharger la configuration lorsque le fichier est modifié :

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
}

Limitations de WatchService

Limitations importantes :

  • Surveille uniquement les répertoires, et non les fichiers individuels
  • La surveillance n’est pas récursive par défaut : enregistrez manuellement chaque sous-répertoire
  • Sous macOS : utilise l’interrogation en interne, et réagit donc moins rapidement que inotify sous Linux
  • Peut manquer des rafales rapides de modifications (OVERFLOW)
  • Le WatchKey devient invalide si le répertoire surveillé est supprimé

Vérification rapide

Après avoir traité les événements d’un WatchKey, quelle méthode devez-vous appeler avant que le WatchService puisse transmettre d’autres événements pour cette clé ?

Récapitulatif : WatchService

Points essentiels :

  • Enregistrez les répertoires pour les événements de création, de modification et de suppression
  • take() bloque ; poll() ne bloque pas ; utilisez poll(timeout, unit) pour une attente temporisée
  • Appelez toujours key.reset() après avoir traité les événements
  • context() renvoie uniquement le nom du fichier : résolvez-le par rapport au répertoire surveillé pour obtenir le chemin complet
  • Fermez le WatchService avec une gestion automatique des ressources
  • La surveillance récursive nécessite d’enregistrer chaque sous-répertoire

Questions Fréquemment Posées

La leçon « WatchService : surveiller les changements de fichiers » est-elle gratuite ?

Oui — le texte complet de « WatchService : surveiller les changements de fichiers » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « WatchService : surveiller les changements de fichiers » ?

Enregistrez un WatchService pour détecter en temps réel les événements de création, de modification et de suppression de fichiers. Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Java Academy ?

Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « WatchService : surveiller les changements de fichiers » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?

Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Path : représenter des emplacements de fichiers
  2. Utilitaire Files : lire, écrire, copier, déplacer
  3. Parcourir les arborescences de répertoires avec Files.walk
  4. WatchService : surveiller les changements de fichiers
← Retour à Java Academy