2009-01-30 26 views
91

Me gustaría recibir una notificación cuando se haya cambiado un archivo en el sistema de archivos. No he encontrado más que un hilo que sondea la última propiedad del archivo modificado y, evidentemente, esta solución no es óptima.Escucha modificada de archivo en Java

+0

Gracias por todas las respuestas. Como mis necesidades son pequeñas (solo tengo que volver a cargar un archivo de propiedad en mi aplicación web modificada ... principalmente porque reiniciar toda la aplicación web es un poco lento), me mantendré firme con el modelo de encuesta. Al menos ahora sé que no hay una solución simple para estos casos. – cheng81

+13

Solo una nota. Cuando resolvimos este problema, descubrimos que los archivos grandes tienden a entrar lentamente, y el mecanismo de sondeo a menudo descubría un archivo nuevo o modificado antes de que se escribiera por completo. Para resolver esto, se adoptó una solución de "dos mordiscos". El encuestador notó que un archivo había cambiado, pero no notificó al sistema sobre un archivo nuevo/modificado hasta que parecía el mismo para dos encuestas: es decir, se había estabilizado. Curado una gran cantidad de errores de archivo incorrecto. –

+1

Como un lado, Tomcat sufre ese problema al colocar grandes archivos WAR en la carpeta webapps desde fuentes remotas y lo ha hecho durante mucho tiempo. –

Respuesta

19

En el nivel bajo, la única forma de modelar esta utilidad es realizar un sondeo de hilos en un directorio y controlar los atributos del archivo. Pero puede usar patrones para desarrollar un adaptador para tal utilidad.

Por ejemplo, los servidores de aplicaciones j2ee como Tomcat y otros tienen una característica de carga automática en la que tan pronto como el descriptor de implementación cambia o la clase de servlet cambia, la aplicación se reinicia.

Puede usar las bibliotecas de dichos servidores ya que la mayoría del código de tomcat es reutilizable y de código abierto.

+54

Esto ya no es cierto en Java 7: ahora hay una API para esto que se puede conectar a los servicios de notificación del sistema operativo: http://blogs.oracle.com/thejavatutorials/entry/watching_a_directory_for_changes –

+0

Esa API es muy inadecuada, no lo hace proporcionar notificaciones para eventos de cierre de archivos en Linux. Entonces, dado un caso simple, cuando se cierra un archivo, copiarlo a otro directorio no funciona. –

2

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 ventanas.

http://www.teamdev.com/jniwrapper/index.jsf

De lo contrario, recurrir a código nativo no siempre es algo malo sobre todo cuando la mejor oferta es un mecanismo de sondeo, frente a un evento nativo .

He notado que las operaciones del sistema de archivos java pueden ser lentas en algunas computadoras y pueden afectar fácilmente el rendimiento de las aplicaciones si no se manejan bien.

27

Hay una lib llamada jnotify que envuelve inotify en Linux y también tiene soporte para Windows. Nunca lo usé y no sé lo bueno que es, pero vale la pena intentarlo, diría yo.

+1

Funciona perfectamente y es súper fácil de usar. He estado usando inotify por muchos años. Es rápido, estable y confiable –

102

He escrito un monitor de archivo de registro antes, y encontré que el impacto en el rendimiento del sistema al sondear los atributos de un único archivo, algunas veces por segundo, es realmente muy pequeño.

Java 7, como parte de NIO.2 ha añadido la API WatchService API

El WatchService está diseñado para aplicaciones que necesitan ser notificado sobre los eventos de cambio de archivo.

+7

veo los ejemplos como un directorio de observación, pero ¿qué pasa con un archivo individual? –

+0

@ArchimedesTrajano La API le notifica cuando un archivo en un directorio ha cambiado. El evento que se desencadena incluye el nombre del archivo que ha cambiado. De modo que puede manejar eventos para un cierto archivo o archivos e ignorar otros. – Michael

+0

@ArchimedesTrajano https://stackoverflow.com/questions/16251273/can-i-watch-for-single-file-change-with-watchservice-not-the-whole-directory – user1742529

3

"Más funciones de NIO" tiene funcionalidad de vigilancia de archivos, con implementación dependiente del sistema operativo subyacente. Debería estar en JDK7.

+0

¿Podría ser más específico o publicar un enlace? a la documentación? Parece que no puede encontrar nada en este ... – Luciano

37

que utilizan la API VFS de Apache Commons, aquí es un ejemplo de cómo controlar un archivo sin mucho impacto en el rendimiento:

DefaultFileMonitor

+1

gracias por esta respuesta!exactamente lo que busqué ... –

+0

muy útil, gracias –

1

También puede considerar el Apache Commons JCI (Java Compiler Interface). Aunque esta API parece centrarse en la compilación dinámica de clases, también incluye clases en su API que supervisa los cambios de archivos.

Ejemplo: http://commons.apache.org/jci/usage.html

3

Ejecuto este fragmento de código cada vez que voy a leer el archivo de propiedades, solo leyendo 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; 
} 

Similar approach se utiliza en Log4J FileWatchdog.

7

Java commons-io tiene un FileAlterationObserver. realiza sondeos en combinación con un FileAlterationMonitor. Similar a los VFS comunes. La ventaja es que tiene muchas menos dependencias.

editar: Menos dependencias no son ciertas, son opcionales para VFS. Pero usa el archivo java en lugar de la capa de abstracción VFS.

1

Puede escuchar los cambios de archivos usando 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(); 
    } 
} 
0

Sin embargo, la votación de la última propiedad del archivo modificado es una solución simple pero efectiva. Sólo definir una clase que se extiende mi FileChangedWatcher e implementar 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(); 
} 
0

Al igual que en las otras respuestas, aquí está cómo lo hice usando Archivo, Temporizador y TimerTask para que esta carrera como un sondeo subproceso en segundo plano a intervalos fijos .

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); 
    } 

    } 
} 
Cuestiones relacionadas