Plik zmienił nasłuchiwanie w Javie


104

Chciałbym otrzymać powiadomienie, gdy plik zostanie zmieniony w systemie plików. Nie znalazłem nic poza wątkiem, który sonduje właściwość lastModified File i najwyraźniej to rozwiązanie nie jest optymalne.


Dzięki za wszystkie odpowiedzi. Ponieważ moje potrzeby są małe (potrzebuję tylko przeładować zmieniony plik właściwości w mojej aplikacji internetowej… głównie dlatego, że ponowne uruchamianie całej aplikacji internetowej jest trochę powolne), pozostanę przy modelu ankiety. Przynajmniej teraz wiem, że nie ma prostego rozwiązania dla tych przypadków.
— cheng81

14
Tylko uwaga. Kiedy rozwiązaliśmy ten problem, zanim odkryliśmy, że duże pliki zwykle przychodzą powoli, a mechanizm odpytywania często odkrywał nowy lub zmieniony plik, zanim został w pełni zapisany. Aby rozwiązać ten problem, przyjęto rozwiązanie typu „dwa kęsy”. Ankieter zauważył, że plik uległ zmianie, ale nie powiadomił systemu o nowym / zmienionym pliku, dopóki nie wyglądał tak samo przez dwie ankiety, tj. Nie ustabilizował się. Wyleczono wiele błędnych plików.
— Steve Powell

1
Nawiasem mówiąc, Tomcat ma ten problem podczas upuszczania dużych plików WAR do folderu webapps ze zdalnych źródeł i robi to przez długi czas.
— John Rix

Odpowiedzi:


21

Na niskim poziomie jedynym sposobem modelowania tego narzędzia jest odpytywanie wątków w katalogu i obserwowanie atrybutów pliku. Ale możesz użyć wzorców, aby opracować adapter dla takiego narzędzia.

Na przykład serwery aplikacji j2ee, takie jak Tomcat i inne, mają funkcję automatycznego ładowania, która powoduje ponowne uruchomienie aplikacji po zmianie deskryptora wdrażania lub zmianie klasy serwletu.

Możesz korzystać z bibliotek z takich serwerów, ponieważ większość kodu tomcat jest wielokrotnego użytku i open source.


59
To już nie jest prawdą w Javie 7: istnieje teraz interfejs API, który może podłączyć się do usług powiadamiania systemu operacyjnego: blogs.oracle.com/thejavatutorials/entry/ ...
— Arnout Engelen

Ten interfejs API jest wysoce nieodpowiedni i nie zapewnia powiadomień o zdarzeniach związanych z zamknięciem plików w systemie Linux. Tak więc, biorąc pod uwagę prosty przypadek, gdy plik jest zamknięty, skopiowanie go do innego katalogu nie działa.
— binarytemple_picsolve

117

Napisałem już wcześniej monitor pliku dziennika i odkryłem, że wpływ odpytywania atrybutów pojedynczego pliku kilka razy na sekundę na wydajność systemu jest w rzeczywistości bardzo mały.

Java 7, jako część NIO.2, dodała WatchService API

WatchService API jest przeznaczony dla aplikacji, które muszą być powiadamiane o zdarzeniach dotyczących zmiany plików.


10
widzę przykłady jako obserwację katalogu, ale co z pojedynczym plikiem?
— Archimedes Trajano

@ArchimedesTrajano Interfejs API powiadamia o zmianie pliku w katalogu. Wyzwalane zdarzenie zawiera nazwę pliku, który się zmienił. Możesz więc obsługiwać zdarzenia dla określonego pliku lub plików i ignorować inne.
— Michael



27

Istnieje biblioteka o nazwie jnotify, która otacza inotify w systemie Linux i obsługuje również okna. Nigdy go nie używałem i nie wiem, jakie jest dobre, ale powiedziałbym, że warto spróbować.


1
Działa doskonale i jest super prosty w użyciu. Używam inotify od wielu lat. Jest szybki, stabilny i niezawodny
— oᴉɹǝɥɔ

8

Java commons-io ma FileAlterationObserver . wykonuje odpytywanie w połączeniu z FileAlterationMonitor. Podobny do commons VFS. Zaletą jest to, że ma znacznie mniej zależności.

edycja: mniej zależności nie jest prawdą, są one opcjonalne dla VFS. Ale używa pliku java zamiast warstwy abstrakcji VFS.


4

„Więcej funkcji NIO” ma funkcję monitorowania plików, której implementacja zależy od bazowego systemu operacyjnego. Powinien być w JDK7.


Czy mógłbyś być bardziej szczegółowy lub zamieścić link do dokumentacji? Nie mogę znaleźć niczego na ten temat ...
— Luciano,

Wydaje się, że to pakiet java.nio.file. Zobacz samouczek .
— David L.

4

Uruchamiam ten fragment kodu za każdym razem, gdy czytam plik właściwości, w rzeczywistości czytam plik tylko wtedy, gdy został zmodyfikowany od czasu ostatniego czytania. Mam nadzieję, że to komuś pomoże.

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

Podobne podejście zastosowano w Log4J FileWatchdog.


2

Możesz słuchać zmian plików za pomocą FileReader. Plz zobacz poniższy przykład

// 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

Jeśli chcesz rozstać się z pewnymi pieniędzmi, JNIWrapper jest przydatną biblioteką z pakietem Winpack, będziesz w stanie uzyskać zdarzenia systemu plików w niektórych plikach. Niestety tylko okna.

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

W przeciwnym razie uciekanie się do kodu natywnego nie zawsze jest złą rzeczą, zwłaszcza gdy najlepszą ofertą jest mechanizm odpytywania, a nie zdarzenie natywne.

Zauważyłem, że operacje systemu plików Java mogą być powolne na niektórych komputerach i mogą łatwo wpływać na wydajność aplikacji, jeśli nie są dobrze obsługiwane.


1

Możesz również rozważyć Apache Commons JCI (Java Compiler Interface). Chociaż wydaje się, że ten interfejs API koncentruje się na dynamicznej kompilacji klas, zawiera również klasy w swoim API, które monitorują zmiany plików.

Przykład: http://commons.apache.org/jci/usage.html




1

Sondowanie ostatnio zmodyfikowanej właściwości pliku jest jednak prostym, ale skutecznym rozwiązaniem. Po prostu zdefiniuj klasę rozszerzającą my FileChangedWatcheri zaimplementuj onModified()metodę:

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

Podobnie jak w przypadku innych odpowiedzi, oto jak to zrobiłem za pomocą File, Timer i TimerTask, aby uruchomić to jako sondowanie wątku w tle w ustalonych odstępach czasu.

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

  }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.