0Pricing
Java Academy · Aula

WatchService: Monitoramento de Alterações em Arquivos

Registre um WatchService para detectar em tempo real eventos de criação, modificação e exclusão de arquivos.

WatchService: Monitoramento de Alterações em Arquivos é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

O que é WatchService?

WatchService monitors a directory for file system events: creation, modification, and deletion. It uses OS-level notifications (inotify on Linux, FSEvents on macOS) — much more efficient than polling.

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

Consulta periódica de eventos

Chame watcher.take() para bloquear até que ocorra um evento e, então, processe os 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
}

Consulta sem bloqueio

Use watcher.poll() para verificações sem bloqueio ou poll(timeout, unit) para esperas cronometradas:

// 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

Se os eventos se acumularem mais rapidamente do que a aplicação consegue processá-los, um evento OVERFLOW sinalizará que alguns eventos foram perdidos. Trate essa situação adequadamente:

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
}

Exemplo completo em funcionamento

Um observador completo de arquivos executado em uma thread em 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();
            }
        }
    }
}

Observação de vários diretórios

Registre vários diretórios com o mesmo WatchService. Use o WatchKey retornado para identificar de qual diretório veio o 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);

Resolução do caminho completo

O context() do evento retorna apenas o nome do arquivo, não o caminho completo. Resolva-o em relação ao diretório observado:

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

Observação recursiva de diretórios

WatchService observa apenas o diretório registrado, não os respectivos subdiretórios. Para fazer uma observação recursiva, percorra a árvore e registre cada subdiretório:

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

Limpeza de recursos

Sempre feche o WatchService ao terminar para liberar os recursos do 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

Caso prático: recarregamento imediato da configuração

Use WatchService para recarregar a configuração quando o arquivo for alterado:

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
}

Limitações do WatchService

Limitações importantes:

  • Observa apenas diretórios, não arquivos individuais
  • Não é recursivo por padrão: registre cada subdiretório manualmente
  • No macOS: usa consulta periódica internamente, sendo menos responsivo que o inotify do Linux
  • Pode não detectar rajadas rápidas de alterações (OVERFLOW)
  • WatchKey se torna inválido se o diretório observado for excluído

Verificação rápida

Depois de processar os eventos de um WatchKey, o que você deve chamar antes que o WatchService entregue novos eventos para essa chave?

Recapitulação: WatchService

Principais conclusões:

  • Registre diretórios com eventos ENTRY_CREATE/MODIFY/DELETE
  • take() bloqueia; poll() não bloqueia; use poll(timeout, unit) para uma espera cronometrada
  • Sempre chame key.reset() depois de processar os eventos
  • context() retorna apenas o nome do arquivo; resolva-o em relação ao diretório observado para obter o caminho completo
  • Feche o WatchService usando try-with-resources
  • A observação recursiva exige o registro de cada subdiretório

Perguntas Frequentes

A aula “WatchService: Monitoramento de Alterações em Arquivos” é grátis?

Sim — o texto completo de “WatchService: Monitoramento de Alterações em Arquivos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “WatchService: Monitoramento de Alterações em Arquivos”?

Registre um WatchService para detectar em tempo real eventos de criação, modificação e exclusão de arquivos. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “WatchService: Monitoramento de Alterações em Arquivos”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Path: Representação de Locais de Arquivos
  2. Utilitário Files: Ler, Escrever, Copiar e Mover
  3. Percurso de Árvores de Diretórios com Files.walk
  4. WatchService: Monitoramento de Alterações em Arquivos
← Voltar para Java Academy