Прослушиватель измененных файлов в Java

Я хотел бы быть уведомлены, когда файл был изменен в файловой системе. Я не нашел ничего, кроме потока, который опрашивает свойство lastModified File и, очевидно, это решение не является оптимальным.

14 ответов


на низком уровне единственным способом моделирования этой утилиты является опрос потока в каталоге и наблюдение за атрибутами файла. Но вы можете использовать шаблоны для разработки адаптера для такой утилиты.

например, серверы приложений j2ee, такие как Tomcat и другие, имеют функцию автоматической загрузки, где, как только изменяется дескриптор развертывания или класс сервлета, приложение перезапускается.

вы можете использовать библиотеки с таких серверов, как большинство код tomcat является многоразовым и открытым.


Я уже писал монитор файлов журнала раньше, и я обнаружил, что влияние на производительность системы опроса атрибутов одного файла, несколько раз в секунду, на самом деле очень мало.

Java 7, как часть NIO.2 добавил WatchService API

API WatchService предназначен для приложений, которые должны быть уведомлены о событиях изменения файлов.


Я использую API VFS из Apache Commons, вот пример того, как отслеживать файл без особого влияния на производительность:

DefaultFileMonitor


существует lib под названием jnotify, который обертывает inotify на linux, а также имеет поддержку windows. Никогда не использовал его, и я не знаю, насколько он хорош, но я бы сказал, что стоит попробовать.


Java commons-io имеет FileAlterationObserver. он делает опрос в сочетании с FileAlterationMonitor. Похож на commons VFS. Преимущество в том, что у него гораздо меньше зависимостей.

edit: меньше зависимостей неверно, они необязательны для VFS. Но он использует java-файл вместо слоя абстракции VFS.


"больше функций NIO" имеет функциональность просмотра файлов, с реализацией, зависящей от базовой ОС. Должно быть в JDK7.


Я запускаю этот фрагмент кода каждый раз, когда я иду читать файл свойств, только фактически читая файл, если он был изменен с момента последнего чтения. Надеюсь, это кому-то поможет.

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

аналогичный подход используется в Log4J FileWatchdog.


Если вы готовы расстаться с некоторыми деньгами, jniwrapper-это полезная библиотека с Winpack, вы сможете получить события файловой системы на определенных файлах. К сожалению, только windows.

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

в противном случае обращение к родному коду не всегда плохо, особенно когда лучшим вариантом является механизм опроса против родного события.

Я заметил, что операции файловой системы java могут быть медленными на некоторых компьютеры и могут легко повлиять на производительность приложений, если не обрабатываются хорошо.


вы также можете рассмотреть Apache Commons JCI (интерфейс компилятора Java). Хотя этот API, похоже, ориентирован на динамическую компиляцию классов, он также включает классы в свой API, который отслеживает изменения файлов.

пример: http://commons.apache.org/jci/usage.html


Spring интеграция обеспечивает хороший механизм для просмотра каталогов и файлов:http://static.springsource.org/spring-integration/reference/htmlsingle/#files. Довольно уверен, что это кросс-платформа (я использовал ее на mac, linux и windows).


вы можете прослушивать изменения файлов с помощью FileReader. Plz см. пример ниже

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

существует коммерческая кросс-настольная библиотека для просмотра файлов и папок под названием JxFileWatcher. Его можно скачать отсюда: http://www.teamdev.com/jxfilewatcher/

также вы можете увидеть его в действии онлайн: http://www.teamdev.com/jxfilewatcher/onlinedemo/


подобно другим ответам, вот как я сделал это с помощью файла, таймера и TimerTask, чтобы это работало как опрос фонового потока с заданными интервалами.

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

  }
}

опрос последнего измененного свойства файла является простым, но эффективным решением. Просто определите класс, расширяющий my FileChangedWatcher и реализовать 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();
}