Een gids voor WatchService in Java NIO2

1. Overzicht

In dit artikel gaan we de WatchService interface van Java NIO.2-bestandssysteem-API's. Dit is een van de minder bekende functies van de nieuwere IO-API's die daarnaast in Java 7 zijn geïntroduceerd FileVisitor koppel.

Om de WatchService interface in uw applicaties, moet u de juiste klassen importeren:

importeer java.nio.file. *;

2. Waarom gebruiken WatchService

Een bekend voorbeeld om te begrijpen wat de service doet, is eigenlijk de IDE.

Het is je misschien opgevallen dat de IDE's altijd detecteert een wijziging in broncodebestanden dat gebeurt buiten zichzelf. Sommige IDE's informeren u via een dialoogvenster, zodat u ervoor kunt kiezen om het bestand opnieuw te laden vanuit het bestandssysteem of niet, andere werken het bestand eenvoudigweg op de achtergrond bij.

Evenzo doen nieuwere frameworks zoals Play ook standaard het hot herladen van de applicatiecode - telkens wanneer u bewerkingen uitvoert vanuit een willekeurige editor.

Deze applicaties maken gebruik van een functie genaamd melding van bestandswijziging dat beschikbaar is in alle bestandssystemen.

Eigenlijk, we kunnen code schrijven om het bestandssysteem te onderzoeken op wijzigingen in specifieke bestanden en mappen. Deze oplossing is echter niet schaalbaar, vooral als de bestanden en mappen honderden en duizenden bereiken.

In Java 7 NIO.2 is de WatchService API biedt een schaalbare oplossing voor het controleren van mappen op wijzigingen. Het heeft een schone API en is zo goed geoptimaliseerd voor prestaties dat we onze eigen oplossing niet hoeven te implementeren.

3. Hoe werkt de wachtdienst?

Om de WatchService functies, is de eerste stap het maken van een WatchService instantie met behulp van de java.nio.file.FileSystems klasse:

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

Vervolgens moeten we het pad maken naar de map die we willen bewaken:

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

Na deze stap moeten we het pad registreren bij de bewakingsservice. Er zijn in dit stadium twee belangrijke concepten die u moet begrijpen. De StandardWatchEventKinds klasse en de WatchKey klasse. Bekijk de volgende registratiecode om te begrijpen waar elke valpartij is. We zullen dit volgen met uitleg van hetzelfde:

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

Merk hier slechts twee belangrijke dingen op: Ten eerste neemt de padregistratie API-aanroep de watch service-instantie als de eerste parameter, gevolgd door variabele argumenten van StandardWatchEventKinds. Ten tweede is het retourtype van het registratieproces een WatchKey voorbeeld.

3.1. De StandardWatchEventKinds

Dit is een klasse waarvan de instanties de bewakingsdienst vertellen op welke soorten gebeurtenissen ze moet letten in de geregistreerde directory. Er zijn momenteel vier mogelijke evenementen om naar te kijken:

  • StandardWatchEventKinds.ENTRY_CREATE - wordt geactiveerd wanneer er een nieuwe vermelding wordt gemaakt in de bewaakte directory. Het kan komen door het aanmaken van een nieuw bestand of het hernoemen van een bestaand bestand.
  • StandardWatchEventKinds.ENTRY_MODIFY - wordt geactiveerd wanneer een bestaand item in de bewaakte directory wordt gewijzigd. Alle bewerkingen van bestanden activeren deze gebeurtenis. Op sommige platforms zal zelfs het wijzigen van bestandskenmerken het activeren.
  • StandardWatchEventKinds.ENTRY_DELETE - wordt geactiveerd wanneer een item wordt verwijderd, verplaatst of hernoemd in de bewaakte directory.
  • StandardWatchEventKinds.OVERFLOW - geactiveerd om verloren of weggegooide gebeurtenissen aan te geven. We zullen er niet veel op focussen

3.2. De WatchKey

Deze klasse vertegenwoordigt de registratie van een directory bij de bewakingsdienst. Het exemplaar wordt door de bewakingsdienst naar ons teruggestuurd wanneer we een directory registreren en wanneer we de bewakingsdienst vragen of er gebeurtenissen hebben plaatsgevonden waarvoor we ons hebben geregistreerd.

Watch-service biedt ons geen callback-methoden die worden aangeroepen wanneer zich een gebeurtenis voordoet. We kunnen het alleen op een aantal manieren opvragen om deze informatie te vinden.

We kunnen de poll API:

WatchKey watchKey = watchService.poll ();

Deze API-aanroep keert meteen terug. Het retourneert de volgende wachtsleutel in de wachtrij waarvan een van de gebeurtenissen is opgetreden of nul als er geen geregistreerde gebeurtenissen hebben plaatsgevonden.

We kunnen ook een overbelaste versie gebruiken waarvoor een time-out argument:

WatchKey watchKey = watchService.poll (lange time-out, TimeUnit-eenheden);

Deze API-aanroep lijkt qua retourwaarde op de vorige. Het blokkeert echter voor time-out tijdseenheden om meer tijd te geven waarbinnen een gebeurtenis kan plaatsvinden in plaats van meteen null te retourneren.

Ten slotte kunnen we de nemen API:

WatchKey watchKey = watchService.take ();

Deze laatste benadering blokkeert eenvoudig totdat er een gebeurtenis plaatsvindt.

We moeten hier iets heel belangrijks opmerken: wanneer de WatchKey instantie wordt geretourneerd door een van de poll of nemen API's, het zal niet meer gebeurtenissen vastleggen als de reset-API niet wordt aangeroepen:

watchKey.reset ();

Dit betekent dat de instantie van de bewakingssleutel wordt verwijderd uit de wachtrij van de bewakingsdienst telkens wanneer deze wordt geretourneerd door een peilingoperatie. De resetten API-aanroep plaatst het terug in de wachtrij om op meer evenementen te wachten.

De meest praktische toepassing van de watcher-service zou een lus vereisen waarin we continu controleren op wijzigingen in de bewaakte directory en dienovereenkomstig verwerken. We kunnen het volgende idioom gebruiken om dit te implementeren:

WatchKey-sleutel; while ((key = watchService.take ())! = null) {voor (WatchEvent event: key.pollEvents ()) {// process} key.reset (); }

We maken een wachtsleutel om de geretourneerde waarde van de peilingoperatie op te slaan. De while-lus wordt geblokkeerd totdat de voorwaardelijke instructie wordt geretourneerd met een watch-toets of null.

Als we een wachtsleutel krijgen, voert de while-lus de code erin uit. Wij gebruiken de WatchKey.pollEvents API om een ​​lijst met gebeurtenissen te retourneren die hebben plaatsgevonden. We gebruiken dan een voor elk loop om ze een voor een te verwerken.

Nadat alle gebeurtenissen zijn verwerkt, moeten we de resetten API om de wachtsleutel opnieuw in de wachtrij te plaatsen.

4. Voorbeeld van directory-kijken

Omdat we de WatchService API in de vorige paragraaf en hoe het intern werkt en ook hoe we het kunnen gebruiken, we kunnen nu doorgaan en naar een compleet en praktisch voorbeeld kijken.

Om draagbaarheidsredenen gaan we kijken naar activiteit in de homedirectory van de gebruiker, die beschikbaar zou moeten zijn op alle moderne besturingssystemen.

De code bevat slechts een paar regels code, dus we zullen het gewoon in de hoofdmethode houden:

openbare klasse DirectoryWatcherExample {openbare statische leegte hoofd (String [] args) {WatchService watchService = FileSystems.getDefault (). newWatchService (); Padpad = Paths.get (System.getProperty ("user.home")); path.register (watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); WatchKey-sleutel; while ((key = watchService.take ())! = null) {for (WatchEvent event: key.pollEvents ()) {System.out.println ("Event soort:" + event.kind () + ". Bestand beïnvloed : "+ event.context () +". "); } key.reset (); }}}

En dat is alles wat we echt hoeven te doen. Nu kunt u de klas starten om een ​​directory te bekijken.

Wanneer u naar de basismap van de gebruiker navigeert en elke bestandsmanipulatieactiviteit uitvoert, zoals het maken van een bestand of map, het wijzigen van de inhoud van een bestand of zelfs het verwijderen van een bestand, wordt het allemaal gelogd op de console.

Aangenomen dat u bijvoorbeeld naar de startpagina van de gebruiker gaat, klikt u met de rechtermuisknop in de spatiebalk en selecteert u `nieuw -> bestand` om een ​​nieuw bestand te maken en het vervolgens een naam te geven testFile. Vervolgens voeg je wat inhoud toe en sla je op. De uitvoer op de console ziet er als volgt uit:

Soort evenement: ENTRY_CREATE. Betrokken bestand: nieuw tekstdocument.txt. Soort evenement: ENTRY_DELETE. Betrokken bestand: nieuw tekstdocument.txt. Soort evenement: ENTRY_CREATE. Betrokken bestand: testFile.txt. Soort evenement: ENTRY_MODIFY. Betrokken bestand: testFile.txt. Soort evenement: ENTRY_MODIFY. Betrokken bestand: testFile.txt.

Voel je vrij om het pad te bewerken zodat het verwijst naar een map die je wilt bekijken.

5. Conclusie

In dit artikel hebben we enkele van de minder vaak gebruikte functies onderzocht die beschikbaar zijn in de Java 7 NIO.2-bestandssysteem-API's, met name de WatchService koppel.

We zijn er ook in geslaagd om de stappen te doorlopen van het bouwen van een directory-watch-applicatie om de functionaliteit te demonstreren.

En, zoals altijd, is de volledige broncode voor de voorbeelden die in dit artikel worden gebruikt, beschikbaar in het Github-project.