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

104

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

cheng81
источник
Спасибо за все ответы. Поскольку мои потребности невелики (мне нужно только перезагрузить файл свойств, измененный в моем веб-приложении .. в основном потому, что перезапуск всего веб-приложения происходит довольно медленно), я буду придерживаться модели опроса. По крайней мере, теперь я знаю, что для этих случаев нет простого решения.
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 уведомляет вас об изменении файла в каталоге. Запускаемое событие включает имя файла, который был изменен. Таким образом, вы можете обрабатывать события для определенного файла или файлов и игнорировать другие.
Майкл
@ArchimedesTrajano stackoverflow.com/questions/16251273/…
user1742529
39

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

DefaultFileMonitor

Telcontar
источник
27

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

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

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

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

Христианин
источник
4

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

Том Хотин - tackline
источник
Не могли бы вы уточнить или разместить ссылку на документацию? Кажется, не могу найти ничего на этом ...
Лучано
Вроде пакет 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 могут быть медленными на некоторых компьютерах и могут легко повлиять на производительность приложения, если с ними не справиться.

jdh80
источник
1

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

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

Onejigtwojig
источник
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();
}
BullyWiiPlaza
источник
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);
    }

  }
}
sjsperry
источник