Tôi muốn được thông báo khi một tệp đã được thay đổi trong hệ thống tệp. Tôi không tìm thấy gì ngoài một chuỗi thăm dò thuộc tính LastModified File và rõ ràng giải pháp này không phải là tối ưu.
Tôi muốn được thông báo khi một tệp đã được thay đổi trong hệ thống tệp. Tôi không tìm thấy gì ngoài một chuỗi thăm dò thuộc tính LastModified File và rõ ràng giải pháp này không phải là tối ưu.
Câu trả lời:
Ở cấp độ thấp, cách duy nhất để tạo mô hình tiện ích này là có một chuỗi thăm dò trên một thư mục và theo dõi các thuộc tính của tệp. Nhưng bạn có thể sử dụng các mẫu để phát triển một bộ điều hợp cho một tiện ích như vậy.
Ví dụ, các máy chủ ứng dụng j2ee như Tomcat và các máy chủ khác có tính năng tự động tải trong đó ngay khi bộ mô tả triển khai thay đổi hoặc lớp servlet thay đổi, ứng dụng sẽ khởi động lại.
Bạn có thể sử dụng các thư viện từ các máy chủ như vậy vì hầu hết mã của tomcat đều có thể sử dụng lại và mã nguồn mở.
Tôi đã viết một trình theo dõi tệp nhật ký trước đây và tôi nhận thấy rằng tác động đến hiệu suất hệ thống của việc thăm dò các thuộc tính của một tệp, một vài lần một giây, thực sự là rất nhỏ.
Java 7, là một phần của NIO.2 đã thêm API WatchService
API WatchService được thiết kế cho các ứng dụng cần được thông báo về các sự kiện thay đổi tệp.
Tôi sử dụng VFS API từ Apache Commons, đây là ví dụ về cách giám sát tệp mà không ảnh hưởng nhiều đến hiệu suất:
Có một lib tên là jnotify bao bọc inotify trên linux và cũng có hỗ trợ cho windows. Chưa bao giờ sử dụng nó và tôi không biết nó tốt như thế nào, nhưng nó đáng để thử tôi sẽ nói.
Java commons-io có FileAlterationObserver . nó thực hiện bỏ phiếu kết hợp với FileAlterationMonitor. Tương tự như commons VFS. Ưu điểm là nó có ít phụ thuộc hơn nhiều.
chỉnh sửa: Ít phụ thuộc hơn là không đúng, chúng là tùy chọn cho VFS. Nhưng nó sử dụng tệp java thay vì lớp trừu tượng VFS.
"Các tính năng NIO khác" có chức năng xem tệp, với việc triển khai phụ thuộc vào hệ điều hành cơ bản. Nên ở JDK7.
Tôi chạy đoạn mã này mỗi khi đọc tệp thuộc tính, chỉ thực sự đọc tệp nếu nó đã được sửa đổi kể từ lần cuối cùng tôi đọc. Hy vọng điều này sẽ giúp ai đó.
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;
}
Cách tiếp cận tương tự được sử dụng trong Log4J FileWatchdog
.
Bạn có thể nghe các thay đổi của tệp bằng FileReader. Xin vui lòng xem ví dụ bên dưới
// 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();
}
}
Nếu bạn sẵn sàng chia tay với một số tiền, JNIWrapper là một thư viện hữu ích với Winpack, bạn sẽ có thể nhận các sự kiện hệ thống tệp trên một số tệp nhất định. Thật không may, chỉ có cửa sổ.
Xem https://www.teamdev.com/jniwrapper .
Nếu không, việc sử dụng mã gốc không phải lúc nào cũng là một điều xấu, đặc biệt khi ưu đãi tốt nhất được cung cấp là cơ chế bỏ phiếu chống lại một sự kiện gốc.
Tôi nhận thấy rằng các hoạt động của hệ thống tệp Java có thể chậm trên một số máy tính và có thể dễ dàng ảnh hưởng đến hiệu suất của ứng dụng nếu không được xử lý tốt.
Bạn cũng có thể xem xét Apache Commons JCI (Giao diện trình biên dịch Java). Mặc dù API này dường như tập trung vào việc biên dịch động các lớp, nhưng nó cũng bao gồm các lớp trong API của nó để giám sát các thay đổi của tệp.
Spring Integration cung cấp một cơ chế tốt để xem Thư mục và tệp: http://static.springsource.org/spring-integration/reference/htmlsingle/#files . Khá chắc chắn rằng nó đa nền tảng (tôi đã sử dụng nó trên mac, linux và windows).
Có một thư viện thương mại trên nhiều máy tính để bàn cho các tệp và thư mục đang xem được gọi là JxFileWatcher. Nó có thể được tải xuống từ đây: http://www.teamdev.com/jxfilewatcher/
Ngoài ra, bạn có thể xem nó hoạt động trực tuyến: http://www.teamdev.com/jxfilewatcher/onlineemo/
Tuy nhiên, thăm dò thuộc tính tệp được sửa đổi cuối cùng là một giải pháp đơn giản nhưng hiệu quả. Chỉ cần xác định một lớp mở rộng của tôi FileChangedWatcher
và triển khai onModified()
phương thức:
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();
}
Tương tự như các câu trả lời khác, đây là cách tôi đã thực hiện bằng cách sử dụng File, Timer và TimerTask để cho phép điều này chạy dưới dạng thăm dò luồng nền tại các khoảng thời gian đã định.
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);
}
}
}