Слушатель измененного файла в Java


104

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


Спасибо за все ответы. Поскольку мои потребности невелики (мне нужно только перезагрузить файл свойств, измененный в моем веб-приложении .. в основном потому, что перезапуск всего веб-приложения происходит довольно медленно), я буду придерживаться модели опроса. По крайней мере, теперь я знаю, что для этих случаев нет простого решения.
cheng81

14
Просто примечание. Когда мы решили эту проблему раньше, мы обнаружили, что большие файлы, как правило, поступают медленно, а механизм опроса часто обнаруживал новый или измененный файл до того, как он был полностью записан. Чтобы решить эту проблему, было принято решение «на два укуса». Опрашивающий заметил, что файл был изменен, но не уведомил систему о новом / измененном файле, пока он не выглядел одинаково для двух опросов: т.е. не стабилизировался. Вылечил множество ошибок с плохими файлами.
Стив Пауэлл,

1
Кроме того, Tomcat страдает от этой проблемы при перетаскивании больших файлов WAR в папку webapps из удаленных источников и делает это уже долгое время.
Джон Рикс

Ответы:


21

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

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

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


59
Это больше не так в Java 7: теперь для этого есть API, который может подключаться к службам уведомлений ОС: blogs.oracle.com/thejavatutorials/entry/…
Энгелен,

Этот API крайне неадекватен, он не предоставляет уведомления о событиях закрытия файлов в Linux. Итак, в простом случае, когда файл закрыт, скопировать его в другой каталог не получится.
binarytemple_picsolve

117

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

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

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


10
я рассматриваю примеры как каталог для просмотра, но как насчет отдельного файла?
Archimedes Trajano

@ArchimedesTrajano API уведомляет вас об изменении файла в каталоге. Запускаемое событие включает имя файла, который был изменен. Таким образом, вы можете обрабатывать события для определенного файла или файлов и игнорировать другие.
Майкл


39

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

DefaultFileMonitor


27

Существует библиотека jnotify, которая обертывает inotify в Linux, а также поддерживает Windows. Никогда не использовал, и я не знаю, насколько он хорош, но я бы сказал, что попробовать стоит.


1
Он отлично работает и очень прост в использовании. Пользуюсь inotify много лет. Это быстрый, стабильный и надежный
oᴉɹǝɥɔ

8

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

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


4

«Дополнительные функции NIO» включают функцию отслеживания файлов, реализация которой зависит от базовой ОС. Должен быть в JDK7.


Не могли бы вы уточнить или разместить ссылку на документацию? Кажется, не могу найти ничего на этом ...
Лучано

Вроде пакет java.nio.file. См. Учебник .
Дэвид Л.

4

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

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.


2

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

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

2

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

См. Https://www.teamdev.com/jniwrapper .

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

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


1

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

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




1

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

0

Как и в других ответах, вот как я это сделал, используя File, Timer и 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);
    }

  }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.