WatchService jest mechanizmem wprowadzonym w Javie 7. Pozwala on na obserwowanie interesującego nas folderu. Jeśli przykładowo w obserwowanym folderze pojawi się nowy plik, otrzymamy zdarzenie informujące o tej zmianie. Jest to bardziej wydaje rozwiązanie niż każdorazowe odpytywanie systemu o to czy pojawiły się nowe pliki.

Tworzenie

Aby stworzyć nowy WatchService korzystamy z klasy FileSystems, która zwraca metody związane z aktualnym systemem operacyjnym. Klasa ta pozwala stworzyć WatchService zależny od aktualnego systemu operacyjnego:

WatchService watchService = FileSystems.getDefault().newWatchService();

Po utworzeniu usługi do nasłuchiwania pora na wskazanie miejsca, które chcemy obserwować.

Rejestrowanie

Każda klasa implementująca interfejs java.nio.file.Watchable otrzymała metodę WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events). Metoda ta pozwala zarejestrować stworzony przez nas WatchService. Podczas rejestracji musimy określić na jakie zdarzenia chcemy nasłuchiwać:

  • ENTRY_CREATE - nowy plik został stworzony
  • ENTRY_DELETE - plik został usunięty
  • ENTRY_MODIFY - plik został zmodyfikowany
  • OVERFLOW - informuje o tym, że utraciliśmy informację o zdarzeniu, nie ma potrzeby rejestrowania się na to zdarzenie, aby je otrzymywać

folder.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);

WatchKey

W odpowiedzi na zarejestrowanie WatchService otrzymaliśmy WatchKey. Klasa ta posiada metodę pollEvents(), która zwraca listę zdarzeń WatchEvent. Sam WatchKey może znajdować się w trzech stanach:

  • ready - gotowy do nasłuchiwania (jest w takim stanie zaraz po utworzeniu)
  • signaled - znajduje się w tym stanie po zakolejkowaniu zdarzeń (już więcej nie nasłuchuje!)
  • invalid - znajduje się w tym stanie gdy:
    • WatchService został zamknięty
    • folder przestał być dostępny
    • została wywołana metoda cancel

WatchEvent

Jest to zdarzenie, które wydarzyło się w zarejestrowanym folderze. WatchEvent dostarcza trzy metody:

  • count - ilość wystąpień danego zdarzenia
  • context - nazwa pliku, dla którego zdarzenie wystąpiło
  • kind - typ zdarzenia (uwaga, może być to typ OVERFLOW nawet jeśli się na niego nie rejestrowaliśmy)

watchKey.pollEvents()
.forEach(x -> System.out.format(
“Context: %s Kind: %s Count: %d%n”, x.context(), x.kind().name(), x.count()));

Nasłuchujemy!

Poniżej znajduje się kompletny kod nasłuchujący na zmiany w folderze:

WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get(“dir/path/to/watch”);
WatchKey watchKey = path.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);

while(true) {
watchKey.pollEvents()
.forEach(x -> System.out.format(
“Context: %s Kind: %s Count: %d%n”, x.context(), x.kind().name(), x.count()));
watchKey.reset();
}

Pojawiła się tu metoda reset, która do tej pory nie była opisana. Przypominam, iż WatchKey znajduje się w stanie ready do momentu zakolejkowania pierwszych zdarzeń. Potem nie nasłuchuje on już na nowe zdarzenia. Aby ponownie ustawić WatchKey w stan ready z signaled korzystamy z metody reset.