En guide til WatchService i Java NIO2

1. Oversikt

I denne artikkelen skal vi utforske WatchService grensesnitt for Java NIO.2 filsystem-APIer. Dette er en av de mindre kjente funksjonene til de nyere IO API-ene som ble introdusert i Java 7 ved siden av FileVisitor grensesnitt.

For å bruke WatchService grensesnitt i applikasjonene dine, må du importere de aktuelle klassene:

importer java.nio.file. *;

2. Hvorfor bruke WatchService

Et vanlig eksempel for å forstå hva tjenesten gjør, er faktisk IDE.

Du har kanskje lagt merke til at IDE alltid oppdager en endring i kildekodefiler som skjer utenfor seg selv. Noen IDE-er informerer deg om ved hjelp av en dialogboks slik at du kan velge å laste inn filen på nytt fra filsystemet eller ikke, andre bare oppdaterer filen i bakgrunnen.

På samme måte gjør nyere rammer som Play også varmlading av applikasjonskoden som standard - når du utfører redigeringer fra hvilken som helst redaktør.

Disse applikasjonene benytter en funksjon som heter varsel om filendring som er tilgjengelig i alle filsystemer.

I utgangspunktet, vi kan skrive kode for å avstemme filsystemet for endringer i bestemte filer og kataloger. Imidlertid er denne løsningen ikke skalerbar, spesielt hvis filene og katalogene når hundrevis og tusenvis.

I Java 7 NIO.2 er WatchService API gir en skalerbar løsning for overvåking av kataloger for endringer. Den har et rent API og er så godt optimalisert for ytelse at vi ikke trenger å implementere vår egen løsning.

3. Hvordan fungerer Watchservice?

For å bruke WatchService funksjoner, er det første trinnet å lage en WatchService eksempel bruker java.nio.file.FileSystems klasse:

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

Deretter må vi opprette banen til katalogen vi vil overvåke:

Path path = Paths.get ("pathToDir");

Etter dette trinnet må vi registrere stien hos urtjenesten. Det er to viktige begreper å forstå på dette stadiet. De StandardWatchEventKinds klasse og WatchKey klasse. Ta en titt på følgende registreringskode for å forstå hvor hvert fall. Vi vil følge dette med forklaringer på det samme:

WatchKey watchKey = path.register (watchService, StandardWatchEventKinds ...);

Legg merke til bare to viktige ting her: For det første tar baneregistrerings-API-anropet watch service-forekomsten som den første parameteren etterfulgt av variable argumenter for StandardWatchEventKinds. For det andre er returtypen for registreringsprosessen en WatchKey forekomst.

3.1. De StandardWatchEventKinds

Dette er en klasse hvis forekomster forteller klokketjenesten hva slags hendelser de skal se etter i den registrerte katalogen. Det er for øyeblikket fire mulige arrangementer å se etter:

  • StandardWatchEventKinds.ENTRY_CREATE - utløses når en ny oppføring blir gjort i den overvåkede katalogen. Det kan skyldes opprettelsen av en ny fil eller å gi nytt navn til en eksisterende fil.
  • StandardWatchEventKinds.ENTRY_MODIFY - utløses når en eksisterende oppføring i den overvåkede katalogen endres. All filredigering utløser denne hendelsen. På noen plattformer vil selv endrede filattributter utløse det.
  • StandardWatchEventKinds.ENTRY_DELETE - utløses når en oppføring slettes, flyttes eller omdøpes i den overvåkede katalogen.
  • StandardWatchEventKinds.OVERFLOW - utløst for å indikere tapte eller forkastede hendelser. Vi vil ikke fokusere mye på det

3.2. De WatchKey

Denne klassen representerer registreringen av en katalog hos urtjenesten. Dets forekomst returneres til oss av klokketjenesten når vi registrerer en katalog, og når vi spør klokketjenesten om noen hendelser vi registrerte oss for har skjedd.

Watch-tjenesten gir oss ingen tilbakekallingsmetoder som kalles når en hendelse inntreffer. Vi kan bare avstemme den på en rekke måter for å finne denne informasjonen.

Vi kan bruke avstemming API:

WatchKey watchKey = watchService.poll ();

Denne API-samtalen returnerer med en gang. Den returnerer neste overvåkingstast i kø, hvis hendelser har skjedd eller null hvis ingen registrerte hendelser har skjedd.

Vi kan også bruke en overbelastet versjon som tar en pause argument:

WatchKey watchKey = watchService.poll (lang tidsavbrudd, TimeUnit-enheter);

Denne API-samtalen er lik den forrige i returverdi. Imidlertid blokkerer den for pause tidsenheter for å gi mer tid der en hendelse kan forekomme i stedet for å returnere null med en gang.

Til slutt kan vi bruke ta API:

WatchKey watchKey = watchService.take ();

Denne siste tilnærmingen blokkerer bare til en hendelse inntreffer.

Vi må merke oss noe veldig viktig her: når WatchKey forekomst returneres av en av avstemming eller ta API-er, det vil ikke fange opp flere hendelser hvis API-en ikke tilbakestilles:

watchKey.reset ();

Dette betyr at klokkenøkkelforekomsten blir fjernet fra køtjenestekøen hver gang den returneres av en avstemningsoperasjon. De nullstille API-anrop setter den tilbake i køen for å vente på flere hendelser.

Den mest praktiske anvendelsen av seertjenesten vil kreve en løkke der vi kontinuerlig ser etter endringer i den overvåkede katalogen og behandler deretter. Vi kan bruke følgende form for å implementere dette:

WatchKey-tast; mens ((key = watchService.take ())! = null) {for (WatchEvent hendelse: key.pollEvents ()) {// prosess} key.reset (); }

Vi oppretter en overvåkingsnøkkel for å lagre returverdien til avstemningsoperasjonen. While-sløyfen blokkeres til den betingede setningen returnerer med enten en nøkkel eller null.

Når vi får en klokkeknekk, kjører while-løkken koden i den. Vi bruker WatchKey.pollEvents API for å returnere en liste over hendelser som har skjedd. Vi bruker deretter en for hver loop for å behandle dem en etter en.

Etter at alle hendelsene er behandlet, må vi ringe nullstille API for å innhente klokkeknappen igjen.

4. Eksempel på katalogovervåking

Siden vi har dekket WatchService API i forrige underavsnitt og hvordan det fungerer internt og også hvordan vi kan bruke det, kan vi nå gå videre og se på et komplett og praktisk eksempel.

Av bærbarhetsgrunner skal vi se etter aktivitet i brukerens hjemmekatalog, som skal være tilgjengelig på alle moderne operativsystemer.

Koden inneholder bare noen få kodelinjer, så vi vil bare beholde den i hovedmetoden:

public class DirectoryWatcherExample {public static void main (String [] args) {WatchService watchService = FileSystems.getDefault (). newWatchService (); Banesti = Paths.get (System.getProperty ("user.home")); path.register (watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); WatchKey-tast; while ((key = watchService.take ())! = null) {for (WatchEvent event: key.pollEvents ()) {System.out.println ("Event type:" + event.kind () + ". Fil berørt : "+ event.context () +". "); } key.reset (); }}}

Og det er alt vi virkelig trenger å gjøre. Nå kan du kjøre klassen for å begynne å se på en katalog.

Når du navigerer til brukerens hjemmekatalog og utfører en hvilken som helst filmanipuleringsaktivitet som å lage en fil eller katalog, endre innholdet i en fil eller til og med slette en fil, blir alt logget på konsollen.

For eksempel, forutsatt at du går til brukerens hjem, høyreklikker du i mellomrom og velger `ny -> fil` for å opprette en ny fil og deretter gi den navnet testFile. Deretter legger du til litt innhold og lagrer. Utgangen på konsollen vil se slik ut:

Arrangementstype: ENTRY_CREATE. Berørt fil: Nytt tekstdokument.txt. Arrangementstype: ENTRY_DELETE. Berørt fil: Nytt tekstdokument.txt. Arrangementstype: ENTRY_CREATE. Berørt fil: testFile.txt. Arrangementstype: ENTRY_MODIFY. Berørt fil: testFile.txt. Arrangementstype: ENTRY_MODIFY. Berørt fil: testFile.txt.

Du kan gjerne redigere stien for å peke til hvilken katalog du vil se.

5. Konklusjon

I denne artikkelen har vi utforsket noen av de mindre brukte funksjonene som er tilgjengelige i Java 7 NIO.2 - filsystem-API-er, spesielt WatchService grensesnitt.

Vi har også klart å gå gjennom trinnene for å bygge et katalogtitteapplikasjon for å demonstrere funksjonaliteten.

Og som alltid er hele kildekoden for eksemplene som brukes i denne artikkelen tilgjengelig i Github-prosjektet.