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.
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.
Jawaban:
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.
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.
Saya menggunakan VFS API dari Apache Commons, berikut adalah contoh cara memantau file tanpa banyak berdampak pada kinerja:
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.
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.
"Lebih banyak fitur NIO" memiliki fungsi file watch, dengan implementasi yang bergantung pada OS yang mendasarinya. Harus di JDK7.
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
.
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();
}
}
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.
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.
Spring Integration menyediakan mekanisme yang bagus untuk menonton Direktori dan file: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Cukup yakin ini lintas platform (saya telah menggunakannya di mac, linux, dan windows).
Ada pustaka lintas desktop komersial untuk menonton file dan folder yang disebut JxFileWatcher. Itu dapat diunduh dari sini: http://www.teamdev.com/jxfilewatcher/
Anda juga dapat melihatnya beraksi secara online: http://www.teamdev.com/jxfilewatcher/onlinedemo/
Polling properti file yang terakhir diubah adalah solusi yang sederhana namun efektif. Cukup tentukan kelas yang memperluas saya FileChangedWatcher
dan 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();
}
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);
}
}
}