Chciałbym otrzymać powiadomienie, gdy plik zostanie zmieniony w systemie plików. Nie znalazłem nic poza wątkiem, który sonduje właściwość lastModified File i najwyraźniej to rozwiązanie nie jest optymalne.
Chciałbym otrzymać powiadomienie, gdy plik zostanie zmieniony w systemie plików. Nie znalazłem nic poza wątkiem, który sonduje właściwość lastModified File i najwyraźniej to rozwiązanie nie jest optymalne.
Odpowiedzi:
Na niskim poziomie jedynym sposobem modelowania tego narzędzia jest odpytywanie wątków w katalogu i obserwowanie atrybutów pliku. Ale możesz użyć wzorców, aby opracować adapter dla takiego narzędzia.
Na przykład serwery aplikacji j2ee, takie jak Tomcat i inne, mają funkcję automatycznego ładowania, która powoduje ponowne uruchomienie aplikacji po zmianie deskryptora wdrażania lub zmianie klasy serwletu.
Możesz korzystać z bibliotek z takich serwerów, ponieważ większość kodu tomcat jest wielokrotnego użytku i open source.
Napisałem już wcześniej monitor pliku dziennika i odkryłem, że wpływ odpytywania atrybutów pojedynczego pliku kilka razy na sekundę na wydajność systemu jest w rzeczywistości bardzo mały.
Java 7, jako część NIO.2, dodała WatchService API
WatchService API jest przeznaczony dla aplikacji, które muszą być powiadamiane o zdarzeniach dotyczących zmiany plików.
Używam API VFS z Apache Commons, oto przykład, jak monitorować plik bez większego wpływu na wydajność:
Istnieje biblioteka o nazwie jnotify, która otacza inotify w systemie Linux i obsługuje również okna. Nigdy go nie używałem i nie wiem, jakie jest dobre, ale powiedziałbym, że warto spróbować.
Java commons-io ma FileAlterationObserver . wykonuje odpytywanie w połączeniu z FileAlterationMonitor. Podobny do commons VFS. Zaletą jest to, że ma znacznie mniej zależności.
edycja: mniej zależności nie jest prawdą, są one opcjonalne dla VFS. Ale używa pliku java zamiast warstwy abstrakcji VFS.
„Więcej funkcji NIO” ma funkcję monitorowania plików, której implementacja zależy od bazowego systemu operacyjnego. Powinien być w JDK7.
Uruchamiam ten fragment kodu za każdym razem, gdy czytam plik właściwości, w rzeczywistości czytam plik tylko wtedy, gdy został zmodyfikowany od czasu ostatniego czytania. Mam nadzieję, że to komuś pomoże.
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;
}
Podobne podejście zastosowano w Log4J FileWatchdog
.
Możesz słuchać zmian plików za pomocą FileReader. Plz zobacz poniższy przykład
// 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();
}
}
Jeśli chcesz rozstać się z pewnymi pieniędzmi, JNIWrapper jest przydatną biblioteką z pakietem Winpack, będziesz w stanie uzyskać zdarzenia systemu plików w niektórych plikach. Niestety tylko okna.
Zobacz https://www.teamdev.com/jniwrapper .
W przeciwnym razie uciekanie się do kodu natywnego nie zawsze jest złą rzeczą, zwłaszcza gdy najlepszą ofertą jest mechanizm odpytywania, a nie zdarzenie natywne.
Zauważyłem, że operacje systemu plików Java mogą być powolne na niektórych komputerach i mogą łatwo wpływać na wydajność aplikacji, jeśli nie są dobrze obsługiwane.
Możesz również rozważyć Apache Commons JCI (Java Compiler Interface). Chociaż wydaje się, że ten interfejs API koncentruje się na dynamicznej kompilacji klas, zawiera również klasy w swoim API, które monitorują zmiany plików.
Przykład: http://commons.apache.org/jci/usage.html
Spring Integration zapewnia ładny mechanizm do oglądania katalogów i plików: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Jestem pewien, że jest to platforma wieloplatformowa (używałem jej na komputerach Mac, Linux i Windows).
Istnieje komercyjna biblioteka na różnych pulpitach do oglądania plików i folderów o nazwie JxFileWatcher. Można go pobrać stąd: http://www.teamdev.com/jxfilewatcher/
Możesz również zobaczyć to w akcji online: http://www.teamdev.com/jxfilewatcher/onlinedemo/
Sondowanie ostatnio zmodyfikowanej właściwości pliku jest jednak prostym, ale skutecznym rozwiązaniem. Po prostu zdefiniuj klasę rozszerzającą my FileChangedWatcher
i zaimplementuj onModified()
metodę:
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();
}
Podobnie jak w przypadku innych odpowiedzi, oto jak to zrobiłem za pomocą File, Timer i TimerTask, aby uruchomić to jako sondowanie wątku w tle w ustalonych odstępach czasu.
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);
}
}
}