Me gustaría recibir una notificación cuando se modifique un archivo en el sistema de archivos. No he encontrado nada más que un hilo que sondea la propiedad lastModified File y claramente esta solución no es óptima.
Me gustaría recibir una notificación cuando se modifique un archivo en el sistema de archivos. No he encontrado nada más que un hilo que sondea la propiedad lastModified File y claramente esta solución no es óptima.
Respuestas:
En el nivel bajo, la única forma de modelar esta utilidad es tener un sondeo de subprocesos en un directorio y vigilar los atributos del archivo. Pero puede utilizar patrones para desarrollar un adaptador para dicha utilidad.
Por ejemplo, los servidores de aplicaciones j2ee como Tomcat y otros tienen una función de carga automática en la que tan pronto como cambia el descriptor de implementación o cambia la clase de servlet, la aplicación se reinicia.
Puede usar las bibliotecas de dichos servidores, ya que la mayor parte del código de tomcat es reutilizable y de código abierto.
Escribí un monitor de archivo de registro antes y descubrí que el impacto en el rendimiento del sistema de sondear los atributos de un solo archivo, unas pocas veces por segundo, es en realidad muy pequeño.
Java 7, como parte de NIO.2, ha agregado la API WatchService
La API WatchService está diseñada para aplicaciones que necesitan ser notificadas sobre eventos de cambio de archivo.
Yo uso la API VFS de Apache Commons, aquí hay un ejemplo de cómo monitorear un archivo sin mucho impacto en el rendimiento:
Existe una biblioteca llamada jnotify que incluye inotify en Linux y también tiene soporte para Windows. Nunca lo usé y no sé qué tan bueno es, pero diría que vale la pena intentarlo.
Java commons-io tiene un FileAlterationObserver . realiza encuestas en combinación con un FileAlterationMonitor. Similar a commons VFS. La ventaja es que tiene muchas menos dependencias.
editar: Menos dependencias no es cierto, son opcionales para VFS. Pero usa Java File en lugar de la capa de abstracción VFS.
"Más funciones de NIO" tiene la función de vigilancia de archivos, cuya implementación depende del SO subyacente. Debería estar en JDK7.
Ejecuto este fragmento de código cada vez que voy a leer el archivo de propiedades, y solo leo realmente el archivo si se ha modificado desde la última vez que lo leí. Espero que esto ayude a alguien.
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;
}
En Log4J se utiliza un enfoque similar FileWatchdog
.
Puede escuchar los cambios de archivos utilizando un FileReader. Por favor, vea el ejemplo a continuación
// 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();
}
}
Si está dispuesto a desprenderse de algo de dinero, JNIWrapper es una biblioteca útil con un Winpack, podrá obtener eventos del sistema de archivos en ciertos archivos. Desafortunadamente solo windows.
Consulte https://www.teamdev.com/jniwrapper .
De lo contrario, recurrir al código nativo no siempre es malo, especialmente cuando lo mejor que se ofrece es un mecanismo de sondeo frente a un evento nativo.
He notado que las operaciones del sistema de archivos de Java pueden ser lentas en algunas computadoras y pueden afectar fácilmente el rendimiento de la aplicación si no se manejan bien.
También puede considerar Apache Commons JCI (Interfaz del compilador de Java). Aunque esta API parece estar enfocada en la compilación dinámica de clases, también incluye clases en su API que monitorean los cambios de archivos.
Spring Integration proporciona un buen mecanismo para ver directorios y archivos: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Estoy bastante seguro de que es multiplataforma (lo he usado en mac, linux y windows).
Existe una biblioteca comercial entre escritorios para la visualización de archivos y carpetas llamada JxFileWatcher. Se puede descargar desde aquí: http://www.teamdev.com/jxfilewatcher/
También puede verlo en acción en línea: http://www.teamdev.com/jxfilewatcher/onlinedemo/
Sin embargo, sondear la última propiedad del archivo modificado es una solución simple pero efectiva. Simplemente defina una clase que extienda my FileChangedWatcher
e implemente el onModified()
método:
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();
}
De manera similar a las otras respuestas, así es como lo hice usando File, Timer y TimerTask para permitir que esto se ejecute como un sondeo de subprocesos en segundo plano a intervalos establecidos.
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);
}
}
}