Pregunta

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

¿Fue útil?

Solución

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 usar 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 la clase de servlet cambia 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.

Otros consejos

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, algunas veces por segundo, es en realidad muy pequeño.

Java 7, como parte de NIO.2 ha agregado la WatchService API

  

La API WatchService está diseñada para aplicaciones que necesitan ser notificadas sobre eventos de cambio de archivos.

Utilizo la API VFS de Apache Commons, aquí hay un ejemplo de cómo monitorear un archivo sin mucho impacto en el rendimiento:

DefaultFileMonitor

Hay una biblioteca 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.

Java commons-io tiene un FileAlterationObserver . realiza sondeos en combinación con un FileAlterationMonitor. Similar a los comunes 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 funcionalidad de observación de archivos, con una implementación que depende del sistema operativo subyacente. Debería estar en JDK7.

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

Se utiliza un enfoque similar en Log4J FileWatchdog .

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

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. Lamentablemente solo Windows.

Ver https://www.teamdev.com/jniwrapper .

De lo contrario, recurrir al código nativo no siempre es malo, especialmente 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 la aplicación si no se manejan bien.

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

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

Spring Integration proporciona un mecanismo agradable 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).

Hay una biblioteca comercial de escritorio cruzado para ver archivos y carpetas llamada JxFileWatcher. Se puede descargar desde aquí: http://www.teamdev.com/jxfilewatcher/

También puedes verlo en acción en línea:   http://www.teamdev.com/jxfilewatcher/onlinedemo/

Sondear la última propiedad del archivo modificado es una solución simple pero efectiva. Simplemente defina una clase que extienda mi FileChangedWatcher e implemente el método onModified():

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

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

  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top