WatchService: monitorowanie zmian plików
Rejestruj WatchService, aby w czasie rzeczywistym wykrywać zdarzenia utworzenia, modyfikacji i usunięcia plików.
WatchService: monitorowanie zmian plików to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Czym jest WatchService?
WatchService monitoruje katalog pod kątem zdarzeń systemu plików: tworzenia, modyfikowania i usuwania plików. Korzysta z powiadomień na poziomie systemu operacyjnego (inotify w systemie Linux, FSEvents w systemie macOS) — jest to znacznie wydajniejsze niż odpytywanie.
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);Odpytywanie zdarzeń
Wywołaj watcher.take(), aby zablokować wykonanie do momentu wystąpienia zdarzenia, a następnie przetwórz zdarzenia:
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
}Nieblokujące odpytywanie
Użyj watcher.poll() do nieblokujących sprawdzeń albo poll(timeout, unit), aby zaczekać przez określony czas:
// 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();
}Zdarzenie OVERFLOW
Jeśli zdarzenia gromadzą się szybciej, niż aplikacja jest w stanie je przetwarzać, zdarzenie OVERFLOW sygnalizuje utratę części zdarzeń. Obsłuż je w kontrolowany sposób:
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
}Pełny działający przykład
Kompletny obserwator plików działający w wątku w tle:
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();
}
}
}
}Obserwowanie wielu katalogów
Zarejestruj wiele katalogów w ramach tego samego WatchService. Użyj zwróconego WatchKey, aby określić, z którego katalogu pochodzi zdarzenie:
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);Uzyskiwanie pełnej ścieżki
Metoda context() zwraca tylko nazwę pliku, a nie pełną ścieżkę. Rozwiąż ją względem obserwowanego katalogu:
WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
Path filename = pathEvent.context();
Path fullPath = watchedDir.resolve(filename);
System.out.println("Full path: " + fullPath);Rekurencyjne obserwowanie katalogów
WatchService obserwuje tylko zarejestrowany katalog, a nie jego podkatalogi. Aby obserwować katalogi rekurencyjnie, przejdź po drzewie i zarejestruj każdy podkatalog:
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); }
});
}Zwalnianie zasobów
Po zakończeniu zawsze zamknij WatchService, aby zwolnić zasoby systemu operacyjnego:
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 automaticallyPraktyczny przypadek użycia: przeładowywanie konfiguracji
Użyj WatchService, aby przeładowywać konfigurację po zmianie pliku:
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
}Ograniczenia WatchService
Ważne ograniczenia:
- Obserwuje tylko katalogi, a nie pojedyncze pliki
- Domyślnie nie działa rekurencyjnie — każdy podkatalog trzeba zarejestrować ręcznie
- W systemie macOS: wewnętrznie korzysta z odpytywania (jest mniej responsywny niż inotify w systemie Linux)
- Może pomijać szybko następujące po sobie serie zmian (OVERFLOW)
- WatchKey staje się nieprawidłowy po usunięciu obserwowanego katalogu
Szybkie sprawdzenie
Po przetworzeniu zdarzeń z WatchKey co należy wywołać, zanim WatchService będzie mógł dostarczyć kolejne zdarzenia dla tego klucza?
Podsumowanie: WatchService
Najważniejsze informacje:
- Rejestruj katalogi dla zdarzeń ENTRY_CREATE/MODIFY/DELETE
- take() blokuje wykonanie; poll() jest nieblokujące; poll(timeout, unit) służy do oczekiwania przez określony czas
- Po przetworzeniu zdarzeń zawsze wywołuj key.reset()
- context() zwraca tylko nazwę pliku — aby uzyskać pełną ścieżkę, rozwiąż ją względem obserwowanego katalogu
- Zamykaj WatchService za pomocą try-with-resources
- Obserwowanie rekurencyjne wymaga zarejestrowania każdego podkatalogu
Często zadawane pytania
Czy lekcja „WatchService: monitorowanie zmian plików” jest bezpłatna?
Tak — pełny tekst „WatchService: monitorowanie zmian plików” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „WatchService: monitorowanie zmian plików”?
Rejestruj WatchService, aby w czasie rzeczywistym wykrywać zdarzenia utworzenia, modyfikacji i usunięcia plików. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „WatchService: monitorowanie zmian plików”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Path: reprezentowanie lokalizacji plików
- Narzędzie Files: odczyt, zapis, kopiowanie i przenoszenie
- Przechodzenie po drzewach katalogów za pomocą Files.walk
- WatchService: monitorowanie zmian plików