In questo articolo analizzeremo una libreria Java per il monitoring di directory ed il file changing, in altre parole questa libreria permette di essere avvisati nel momento in cui un file o più file presenti in una directory o una sottodirectory vengono modificati, creati o cancellati. Il funzionamento alla base di questa libreria è quello di rimanere in polling, il cui intervallo può essere cambiato, su di una determinata cartella finchè un dato evento non viene lanciato. In alternativa, per evitare il polling, vengono utilizzate le funzionalità native del Sistema Operativo dell'host su cui vengono utilizzate.
In questo articolo analizzeremo una libreria Java per il monitoring di directory ed il file changing, in altre parole questa libreria permette di essere avvisati nel momento in cui un file o più file presenti in una directory o una sottodirectory vengono modificati, creati o cancellati.
Il funzionamento alla base di questa libreria è quello di rimanere in polling, il cui intervallo può essere cambiato, su di una determinata cartella finchè un dato evento non viene lanciato. In alternativa, per evitare il polling, vengono utilizzate le funzionalità native del Sistema Operativo dell’host su cui vengono utilizzate.
E’ bene ricordare che a partire da Java 7 sono state introdotte delle funzionalità di monitoring dei file con la specifica JSR 203:
http://jcp.org/en/jsr/detail?id=203
in particolare tramite la classe WatchService (http://docs.oracle.com/javase/tutorial/essential/io/notification.html), le funzionalità offerte sono però limitate e vengono supportati solo i Sistemi Operativi Windows e Linux.
Jpathwatch invece implementa le API WatchService, le arricchisce di funzionalità e funziona su numerose piattaforme.
Attualmente vengono supportate nativamente le seguenti piattaforme:
- Windows (Windows 2000, XP, Vista, 7, 32bit/64bit);
- Linux (x86, 32bit/64bit);
- FreeBSD (x86, 32bit);
- Mac OS X
- (x86, 32bit/64bit, testato su 10.5);
- (PPC, testato su 10.4).
Gli eventi che possono essere monitorati su una data directory sono i seguenti:
- la creazione e la cancellazione di un file;
- modifica di un file;
- rinomina di un file*;
- cambiamenti nelle sottodirectory (ricorsivo)*;
- invalidazione (una directory sotto osservazione viene invalidata).
Tipo di evento | Descriz. | Win | Linux | Mac OSX | FreeBSD | Altri |
---|---|---|---|---|---|---|
StandardWatchEventKind .ENTRY_CREATE | file creato | Si | Si | Si | Si | Si* |
StandardWatchEventKind .ENTRY_DELETE | file cancellato | Si | Si | Si | Si | Si* |
StandardWatchEventKind .ENTRY_MODIFY | file modificato | Si | Si | Si* | Si* | Si* |
ExtendedWatchEventKind .ENTRY_RENAME_FROM | file rinominato (vecchio nome) | Si | Si | No | No | No |
ExtendedWatchEventKind .ENTRY_RENAME_TO | file rinominato (nuovo nome) | Si | Si | No | No | No |
ExtendedWatchEventKind .KEY_INVALID | key invalidata (da un utente o un evento esterno) | Si | Si | Si* | Si* | Si* |
Bootstrapper.setForcePollingEnabled(true);
Bootstrapper.getDefaultPollingInterval();
Bootstrapper.setDefaultPollingInterval(10000);
- con la classe Bootstrapper:
WatchService watchService = Bootstrapper.newWatchService();
- con la classe FileSystems:
WatchService watchService = FileSystems.getDefault().newWatchService();
</pre> </div> <div>Path watchedPath = Bootstrapper.newPath(new File("Stringa del path da monitorare"));</div> <div>
WatchKey key = null; try { key = watchedPath.register(watchService, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE,StandardWatchEventKind.ENTRY_MODIFY); } catch (UnsupportedOperationException uox){ System.err.println("Evento di File watching non supportato!"); }catch (IOException iox){ System.err.println("I/O errors"); }
for(;;){ // take() blocca finchè un file non viene creato, modificato o cancellato WatchKey signalledKey=null; try { signalledKey = watchService.take(); } catch (InterruptedException ix){ // ignoriamo l eccezione se qualche altro thread ha chiamato il metodo interrupt sul watch service continue; } catch (ClosedWatchServiceException cwse){ // un altro thread ha chiuso il watch service System.out.println("watch service closed, terminating."); break; } // otteniamo la lista di eventi dall'oggetto key List> list = signalledKey.pollEvents(); // resettiamo la lista di eventi dall'oggetto key signalledKey.reset(); // qui semplicemente stampiamo quello che è successo nella directory monitorata for(WatchEvent e : list){ String message = ""; if(e.kind() == StandardWatchEventKind.ENTRY_CREATE){ Path context = (Path)e.context(); message = context.toString() + " creato"; } else if(e.kind() == StandardWatchEventKind.ENTRY_DELETE){ Path context = (Path)e.context(); message = context.toString() + " cancellato"; } else if(e.kind() == StandardWatchEventKind.ENTRY_MODIFY){ Path context = (Path)e.context(); message = context.toString() + " modificato"; } else if(e.kind() == ExtendedWatchEventKind.ENTRY_RENAME_FROM){ Path context = (Path)e.context(); message = context.toString() + " ridenominato"; }else if(e.kind() == StandardWatchEventKind.OVERFLOW){ message = "OVERFLOW: sono accaduti più cambiamenti di quanti era possibile rilevare"; } System.out.println(message); } }
package it.appuntisoftware; import java.io.File; import java.io.IOException; import java.util.List; import name.pachler.nio.file.*; import name.pachler.nio.file.ext.Bootstrapper; import name.pachler.nio.file.ext.ExtendedWatchEventKind; public class TestJPathWatch { public static void main (String args[]){ new TestJPathWatch().test(); } public void test(){ long mill = Bootstrapper.getDefaultPollingInterval(); System.out.println("Default Polling Interval: "+mill ); Bootstrapper.setDefaultPollingInterval(10000); boolean bool = Bootstrapper.isForcePollingEnabled(); if(!bool) Bootstrapper.setForcePollingEnabled(true); mill = Bootstrapper.getDefaultPollingInterval(); System.out.println("Set Polling Interval: "+mill ); WatchService watchService = Bootstrapper.newWatchService(); Path watchedPath = Bootstrapper.newPath(new File("C:\Documents and Settings\Angelo\Documenti")); WatchKey key = null; try { key = watchedPath.register(watchService, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE,StandardWatch EventKind.ENTRY_MODIFY); } catch (UnsupportedOperationException uox){ System.err.println("Evento di File watching non supportato!"); }catch (IOException iox){ System.err.println("I/O errors"); } for(;;){ // il metodo take() blocca il thread finchè un file non viene creato, modificato o cancellato WatchKey signalledKey=null; try { signalledKey = watchService.take(); } catch (InterruptedException ix){ // ignoriamo l eccezione se qualche altro thread ha chiamato il metodo interrupt sul watch service continue; } catch (ClosedWatchServiceException cwse){ // un altro thread ha chiuso il watch service System.out.println("watch service closed, terminating."); break; } // otteniamo la lista di eventi dall'oggetto key List> list = signalledKey.pollEvents(); // resettiamo la lista di eventi dall'oggetto key signalledKey.reset(); // qui semplicemente stampiamo quello che è successo nella directory monitorata for(WatchEvent e : list){ String message = ""; if(e.kind() == StandardWatchEventKind.ENTRY_CREATE){ Path context = (Path)e.context(); message = context.toString() + " creato"; } else if(e.kind() == StandardWatchEventKind.ENTRY_DELETE){ Path context = (Path)e.context(); message = context.toString() + " cancellato"; } else if(e.kind() == StandardWatchEventKind.ENTRY_MODIFY){ Path context = (Path)e.context(); message = context.toString() + " modificato"; } else if(e.kind() == ExtendedWatchEventKind.ENTRY_RENAME_FROM){ Path context = (Path)e.context(); message = context.toString() + " ridenominato"; }else if(e.kind() == StandardWatchEventKind.OVERFLOW){ message = "OVERFLOW: sono accaduti più cambiamenti di quanti era possibile rilevare"; } System.out.println(message); } } } }
Naturalmente il thread lanciato dal metodo main (il thread principale del nostro programma) si blocca alla chiamata del metodo take(), di conseguenza è preferibile creare un thread secondario da cui lanciare il metodo test() .
COMMENTS