File berubah listener di Java

104

Saya ingin diberi tahu jika file telah diubah di sistem file. Saya tidak menemukan apa-apa selain utas yang memeriksa properti File lastModified dan jelas solusi ini tidak optimal.

cheng81
sumber
Terima kasih atas semua tanggapannya. Karena kebutuhan saya kecil (saya hanya perlu memuat ulang file properti yang diubah di aplikasi web saya..terutama karena memulai ulang seluruh aplikasi web agak lambat), saya akan tetap menggunakan model jajak pendapat. Setidaknya sekarang saya tahu bahwa tidak ada solusi sederhana untuk kasus-kasus ini.
cheng81
14
Hanya sebuah catatan. Ketika kami memecahkan masalah ini sebelum kami menemukan bahwa file besar cenderung masuk dengan lambat, dan mekanisme polling sering menemukan file baru atau file yang diubah sebelum sepenuhnya ditulis. Untuk mengatasi ini, solusi 'dua gigitan' diadopsi. Poller melihat sebuah file telah berubah, tetapi tidak memberi tahu sistem tentang file baru / yang diubah sampai terlihat sama untuk dua polling: yaitu telah stabil. Menyembuhkan banyak error badfile.
Steve Powell
1
Selain itu, Tomcat mengalami masalah itu saat menjatuhkan file WAR besar ke folder webapps dari sumber jarak jauh dan telah melakukannya untuk waktu yang lama.
John Rix

Jawaban:

21

Pada tingkat rendah, satu-satunya cara untuk memodelkan utilitas ini adalah dengan melakukan polling thread pada direktori dan mengawasi atribut file. Tapi Anda bisa menggunakan pola untuk mengembangkan adaptor untuk utilitas semacam itu.

Misalnya server aplikasi j2ee seperti Tomcat dan lainnya memiliki fitur muat otomatis di mana segera setelah perubahan deskripsi penyebaran atau perubahan kelas servlet, aplikasi dimulai ulang.

Anda dapat menggunakan perpustakaan dari server tersebut karena sebagian besar kode tomcat dapat digunakan kembali dan sumber terbuka.

Rutesh Makhijani
sumber
59
Ini tidak lagi benar di Java 7: sekarang ada API untuk ini yang dapat menghubungkan ke layanan notifikasi OS: blogs.oracle.com/thejavatutorials/entry/…
Engelen
API tersebut sangat tidak memadai, tidak memberikan pemberitahuan untuk peristiwa penutupan file di Linux. Jadi, dalam kasus sederhana, ketika file ditutup, salin ke direktori lain tidak berfungsi.
binarytemple_picsolve
117

Saya telah menulis monitor file log sebelumnya, dan saya menemukan bahwa dampak pada kinerja sistem polling atribut dari satu file, beberapa kali dalam satu detik, sebenarnya sangat kecil.

Java 7, sebagai bagian dari NIO.2 telah menambahkan WatchService API

WatchService API dirancang untuk aplikasi yang perlu diberi tahu tentang peristiwa perubahan file.

Stephen Denne
sumber
10
saya melihat contoh sebagai direktori menonton, tetapi bagaimana dengan file individu?
Archimedes Trajano
@ArchimedesTrajano API memberi tahu Anda bila file dalam direktori telah berubah. Peristiwa yang dipicu termasuk nama file yang telah berubah. Jadi, Anda dapat menangani peristiwa untuk file atau file tertentu dan mengabaikan yang lain.
Michael
@ArchimedesTrajano stackoverflow.com/questions/16251273/…
pengguna1742529
39

Saya menggunakan VFS API dari Apache Commons, berikut adalah contoh cara memantau file tanpa banyak berdampak pada kinerja:

DefaultFileMonitor

Telcontar
sumber
27

Ada lib bernama jnotify yang membungkus inotify di linux dan juga mendukung untuk windows. Tidak pernah menggunakannya dan saya tidak tahu seberapa bagusnya, tapi patut dicoba menurut saya.

André
sumber
1
Ini bekerja dengan sempurna dan sangat mudah digunakan. Saya telah menggunakan inotify selama bertahun-tahun. Ini cepat, stabil, dan dapat diandalkan
oᴉɹǝɥɔ
8

Java commons-io memiliki FileAlterationObserver . itu melakukan polling dalam kombinasi dengan FileAlterationMonitor. Mirip dengan commons VFS. Keuntungannya adalah ia memiliki lebih sedikit dependensi.

sunting: Lebih sedikit ketergantungan tidak benar, mereka opsional untuk VFS. Tetapi menggunakan File java, bukan lapisan abstraksi VFS.

Kristen
sumber
4

"Lebih banyak fitur NIO" memiliki fungsi file watch, dengan implementasi yang bergantung pada OS yang mendasarinya. Harus di JDK7.

Tom Hawtin - tackline
sumber
Bisakah Anda lebih spesifik atau memposting tautan ke dokumentasi? Tidak dapat menemukan apapun tentang ini ...
Luciano
Sepertinya itu paketnya java.nio.file. Lihat tutorial .
David L.
4

Saya menjalankan potongan kode ini setiap kali saya pergi untuk membaca file properti, hanya benar-benar membaca file tersebut jika telah dimodifikasi sejak terakhir kali saya membacanya. Semoga ini bisa membantu seseorang.

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

Pendekatan serupa digunakan di Log4J FileWatchdog.

Mike Kramer
sumber
2

Anda dapat mendengarkan perubahan file menggunakan FileReader. Silakan lihat contoh di bawah ini

// 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();
    }
}
Prasanna Sujeewa
sumber
2

Jika Anda ingin berpisah dengan sejumlah uang, JNIWrapper adalah pustaka yang berguna dengan Winpack, Anda akan bisa mendapatkan peristiwa sistem file pada file tertentu. Sayangnya hanya windows.

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

Jika tidak, beralih ke kode native tidak selalu merupakan hal yang buruk terutama jika penawaran terbaik adalah mekanisme polling yang bertentangan dengan peristiwa native.

Saya perhatikan bahwa operasi sistem file Java dapat menjadi lambat di beberapa komputer dan dapat dengan mudah mempengaruhi kinerja aplikasi jika tidak ditangani dengan baik.

jdh80.dll
sumber
1

Anda juga dapat mempertimbangkan Apache Commons JCI (Java Compiler Interface). Meskipun API ini tampaknya difokuskan pada kompilasi dinamis kelas, ia juga menyertakan kelas dalam API-nya yang memantau perubahan file.

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

onejigtwojig
sumber
1

Polling properti file yang terakhir diubah adalah solusi yang sederhana namun efektif. Cukup tentukan kelas yang memperluas saya FileChangedWatcherdan terapkan onModified()metode:

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
sumber
0

Mirip dengan jawaban lain, inilah cara saya melakukannya menggunakan File, Timer, dan TimerTask agar ini berjalan sebagai thread latar belakang polling pada interval yang ditentukan.

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.dll
sumber