Ich möchte benachrichtigt werden, wenn eine Datei im Dateisystem geändert wurde. Ich habe nur einen Thread gefunden, der die lastModified File-Eigenschaft abfragt, und diese Lösung ist eindeutig nicht optimal.
Ich möchte benachrichtigt werden, wenn eine Datei im Dateisystem geändert wurde. Ich habe nur einen Thread gefunden, der die lastModified File-Eigenschaft abfragt, und diese Lösung ist eindeutig nicht optimal.
Antworten:
Auf der niedrigen Ebene besteht die einzige Möglichkeit, dieses Dienstprogramm zu modellieren, darin, einen Thread in einem Verzeichnis abzufragen und die Attribute der Datei zu überwachen. Sie können jedoch Muster verwenden, um einen Adapter für ein solches Dienstprogramm zu entwickeln.
Beispielsweise verfügen j2ee-Anwendungsserver wie Tomcat und andere über eine Funktion zum automatischen Laden, bei der die Anwendung neu gestartet wird, sobald sich der Deployment-Deskriptor oder die Servlet-Klasse ändert.
Sie können die Bibliotheken von solchen Servern verwenden, da der größte Teil des Codes von Tomcat wiederverwendbar und OpenSource ist.
Ich habe bereits einen Protokolldateimonitor geschrieben und festgestellt, dass die Auswirkung der Abfrage der Attribute einer einzelnen Datei einige Male pro Sekunde auf die Systemleistung tatsächlich sehr gering ist.
Java 7 hat als Teil von NIO.2 die WatchService-API hinzugefügt
Die WatchService-API wurde für Anwendungen entwickelt, die über Dateiänderungsereignisse benachrichtigt werden müssen.
Ich verwende die VFS-API von Apache Commons. Hier ist ein Beispiel für die Überwachung einer Datei ohne großen Einfluss auf die Leistung:
Es gibt eine Bibliothek namens jnotify , die inotify unter Linux umschließt und auch Windows unterstützt. Ich habe es nie benutzt und weiß nicht, wie gut es ist, aber es ist einen Versuch wert, würde ich sagen.
Java commons-io verfügt über einen FileAlterationObserver . Es führt eine Abfrage in Kombination mit einem FileAlterationMonitor durch. Ähnlich wie bei Commons VFS. Der Vorteil ist, dass es viel weniger Abhängigkeiten hat.
Bearbeiten: Weniger Abhängigkeiten sind nicht wahr, sie sind für VFS optional. Es wird jedoch Java-Datei anstelle der VFS-Abstraktionsschicht verwendet.
"Weitere NIO-Funktionen" verfügt über eine Dateiüberwachungsfunktion, deren Implementierung vom zugrunde liegenden Betriebssystem abhängt. Sollte in JDK7 sein.
Ich führe dieses Codeausschnitt jedes Mal aus, wenn ich die Eigenschaftendatei lese, und lese die Datei nur dann tatsächlich, wenn sie seit dem letzten Lesen geändert wurde. Hoffe das hilft jemandem.
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;
}
Ein ähnlicher Ansatz wird in Log4J verwendet FileWatchdog
.
Sie können Dateiänderungen mit einem FileReader abhören. Bitte sehen Sie das Beispiel unten
// 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();
}
}
Wenn Sie bereit sind, sich von etwas Geld zu trennen, ist JNIWrapper eine nützliche Bibliothek mit einem Winpack. Sie können Dateisystemereignisse für bestimmte Dateien abrufen. Leider nur Windows.
Siehe https://www.teamdev.com/jniwrapper .
Andernfalls ist der Rückgriff auf nativen Code nicht immer schlecht, insbesondere wenn das beste Angebot ein Abfragemechanismus gegenüber einem nativen Ereignis ist.
Ich habe festgestellt, dass Java-Dateisystemvorgänge auf einigen Computern langsam sein und die Leistung der Anwendung leicht beeinträchtigen können, wenn sie nicht richtig gehandhabt werden.
Sie können auch die Apache Commons JCI (Java Compiler Interface) in Betracht ziehen. Obwohl sich diese API auf die dynamische Kompilierung von Klassen zu konzentrieren scheint, enthält sie auch Klassen in ihrer API, die Dateiänderungen überwachen.
Beispiel: http://commons.apache.org/jci/usage.html
Spring Integration bietet einen nützlichen Mechanismus zum Anzeigen von Verzeichnissen und Dateien: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Ich bin mir ziemlich sicher, dass es plattformübergreifend ist (ich habe es unter Mac, Linux und Windows verwendet).
Es gibt eine kommerzielle Cross-Desktop-Bibliothek für Dateien und Ordner namens JxFileWatcher. Es kann hier heruntergeladen werden: http://www.teamdev.com/jxfilewatcher/
Sie können es auch online in Aktion sehen: http://www.teamdev.com/jxfilewatcher/onlinedemo/
Das Abrufen der zuletzt geänderten Dateieigenschaft ist jedoch eine einfache, aber effektive Lösung. Definieren Sie einfach eine Klasse, die my erweitert, FileChangedWatcher
und implementieren Sie die onModified()
Methode:
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();
}
Ähnlich wie bei den anderen Antworten habe ich Folgendes mit File, Timer und TimerTask gemacht, damit dies in festgelegten Intervallen als Hintergrund-Thread-Abfrage ausgeführt wird.
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);
}
}
}