Vorrei essere avvisato quando un file è stato modificato nel file system. Non ho trovato altro che un thread che esegue il polling della proprietà lastModified File e chiaramente questa soluzione non è ottimale.
Vorrei essere avvisato quando un file è stato modificato nel file system. Non ho trovato altro che un thread che esegue il polling della proprietà lastModified File e chiaramente questa soluzione non è ottimale.
Risposte:
Al livello basso l'unico modo per modellare questa utility è avere un thread che esegue il polling su una directory e tiene sotto controllo gli attributi del file. Ma puoi usare modelli per sviluppare un adattatore per tale utilità.
Ad esempio, i server delle applicazioni j2ee come Tomcat e altri hanno una funzione di caricamento automatico in cui non appena cambia il descrittore di distribuzione o cambia la classe servlet, l'applicazione si riavvia.
È possibile utilizzare le librerie di tali server poiché la maggior parte del codice di Tomcat è riutilizzabile e opensource.
Ho già scritto un monitor di file di registro in precedenza e ho scoperto che l'impatto sulle prestazioni del sistema del polling degli attributi di un singolo file, alcune volte al secondo, è in realtà molto piccolo.
Java 7, come parte di NIO.2, ha aggiunto l' API WatchService
L'API WatchService è progettata per le applicazioni che devono essere informate sugli eventi di modifica dei file.
Uso l'API VFS di Apache Commons, ecco un esempio di come monitorare un file senza molto impatto sulle prestazioni:
C'è una libreria chiamata jnotify che esegue il wrapping di inotify su Linux e ha anche il supporto per Windows. Non l'ho mai usato e non so quanto sia buono, ma vale la pena provare direi.
Java commons-io ha un FileAlterationObserver . esegue il polling in combinazione con un FileAlterationMonitor. Simile a Common VFS. Il vantaggio è che ha molte meno dipendenze.
modifica: Meno dipendenze non è vero, sono opzionali per VFS. Ma usa il file java invece del livello di astrazione VFS.
"Altre funzionalità NIO" ha funzionalità di controllo dei file, con l'implementazione che dipende dal sistema operativo sottostante. Dovrebbe essere in JDK7.
Eseguo questo frammento di codice ogni volta che vado a leggere il file delle proprietà, leggendo il file solo se è stato modificato dall'ultima volta che l'ho letto. Spero che questo aiuti qualcuno.
private long timeStamp;
private File file;
private boolean isFileUpdated( File file ) {
this.file = file;
this.timeStamp = file.lastModified();
if( this.timeStamp != timeStamp ) {
this.timeStamp = timeStamp;
//Yes, file is updated
return true;
}
//No, file is not updated
return false;
}
Un approccio simile viene utilizzato in Log4J FileWatchdog
.
È possibile ascoltare le modifiche ai file utilizzando un FileReader. Per favore guarda l'esempio sotto
// File content change listener
private String fname;
private Object lck = new Object();
...
public void run()
{
try
{
BufferedReader br = new BufferedReader( new FileReader( fname ) );
String s;
StringBuilder buf = new StringBuilder();
while( true )
{
s = br.readLine();
if( s == null )
{
synchronized( lck )
{
lck.wait( 500 );
}
}
else
{
System.out.println( "s = " + s );
}
}
}
catch( Exception e )
{
e.printStackTrace();
}
}
Se sei disposto a separarti con un po 'di soldi, JNIWrapper è una libreria utile con un Winpack, sarai in grado di ottenere eventi del file system su determinati file. Purtroppo solo Windows.
Vedi https://www.teamdev.com/jniwrapper .
Altrimenti, il ricorso al codice nativo non è sempre una cosa negativa, soprattutto quando il meglio in offerta è un meccanismo di polling rispetto a un evento nativo.
Ho notato che le operazioni del file system Java possono essere lente su alcuni computer e possono facilmente influire sulle prestazioni dell'applicazione se non gestite bene.
Puoi anche considerare Apache Commons JCI (Java Compiler Interface). Sebbene questa API sembri essere focalizzata sulla compilazione dinamica di classi, include anche classi nella sua API che monitora le modifiche ai file.
Spring Integration fornisce un bel meccanismo per guardare directory e file: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Abbastanza sicuro che sia multipiattaforma (l'ho usato su Mac, Linux e Windows).
Esiste una libreria commerciale cross-desktop per la visualizzazione di file e cartelle chiamata JxFileWatcher. Può essere scaricato da qui: http://www.teamdev.com/jxfilewatcher/
Inoltre puoi vederlo in azione online: http://www.teamdev.com/jxfilewatcher/onlinedemo/
Il polling dell'ultima proprietà del file modificato è una soluzione semplice ma efficace. Basta definire una classe che estenda my FileChangedWatcher
e implementare il onModified()
metodo:
import java.io.File;
public abstract class FileChangedWatcher
{
private File file;
public FileChangedWatcher(String filePath)
{
file = new File(filePath);
}
public void watch() throws InterruptedException
{
long currentModifiedDate = file.lastModified();
while (true)
{
long newModifiedDate = file.lastModified();
if (newModifiedDate != currentModifiedDate)
{
currentModifiedDate = newModifiedDate;
onModified();
}
Thread.sleep(100);
}
}
public String getFilePath()
{
return file.getAbsolutePath();
}
protected abstract void onModified();
}
Simile alle altre risposte, ecco come l'ho fatto usando File, Timer e TimerTask per farlo funzionare come un thread di polling in background a intervalli prestabiliti.
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
public class FileModifiedWatcher
{
private static File file;
private static int pollingInterval;
private static Timer fileWatcher;
private static long lastReadTimeStamp = 0L;
public static boolean init(String _file, int _pollingInterval)
{
file = new File(_file);
pollingInterval = _pollingInterval; // In seconds
watchFile();
return true;
}
private static void watchFile()
{
if ( null == fileWatcher )
{
System.out.println("START");
fileWatcher = new Timer();
fileWatcher.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
if ( file.lastModified() > lastReadTimeStamp )
{
System.out.println("File Modified");
}
lastReadTimeStamp = System.currentTimeMillis();
}
}, 0, 1000 * pollingInterval);
}
}
}