2009-01-30 28 views
91

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 đã tìm thấy gì, nhưng một chủ đề mà thăm dò tài sản LastModified File và rõ ràng giải pháp này không phải là tối ưu.Người nghe đã thay đổi tệp trong Java

+0

Cảm ơn tất cả các câu trả lời. Vì nhu cầu của tôi là nhỏ (tôi chỉ cần tải lại một tệp tin thuộc tính đã thay đổi trong ứng dụng web của tôi .. chính vì việc khởi động lại toàn bộ webapp là chậm), tôi sẽ giữ nguyên mô hình thăm dò ý kiến. Ít nhất bây giờ tôi biết rằng không có một giải pháp đơn giản cho các trường hợp đề tài. – cheng81

+13

Chỉ cần lưu ý. Khi chúng tôi giải quyết vấn đề này trước khi chúng tôi thấy rằng các tệp lớn có xu hướng chậm, và cơ chế bỏ phiếu thường phát hiện một tệp mới hoặc đã thay đổi trước khi tệp được viết hoàn toàn. Để giải quyết điều này, một giải pháp 'cắn hai' đã được áp dụng. Các poller nhận thấy một tập tin đã thay đổi, nhưng không thông báo cho hệ thống của một tập tin mới/thay đổi cho đến khi nó trông giống nhau cho hai cuộc thăm dò: tức là đã ổn định. Chữa khỏi rất nhiều lỗi badfile. –

+1

Là một sang một bên, Tomcat bị vấn đề đó khi thả các tệp WAR lớn vào thư mục webapps từ các nguồn từ xa và đã làm như vậy trong một thời gian dài. –

Trả lời

19

Ở cấp độ thấp, cách duy nhất để lập mô hình tiện ích này là có một cuộc thăm dò chuỗi trên một thư mục và giữ một chiếc đồng hồ trên 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ụ: máy chủ ứng dụng j2ee như Tomcat và các máy chủ khác có tính năng tải tự động trong đó ngay sau khi thay đổi bộ mô tả triển khai hoặc lớp servlet thay đổi ứng dụng khởi động lại.

Bạn có thể sử dụng các thư viện từ các máy chủ như hầu hết mã của tomcat đều có thể sử dụng lại và được mở.

+54

Điều này không còn đúng trong Java 7: bây giờ có một API cho điều này có thể móc vào các dịch vụ thông báo của hệ điều hành: http://blogs.oracle.com/thejavatutorials/entry/watching_a_directory_for_changes –

+0

API đó là không đủ, nó không cung cấp thông báo cho các sự kiện đóng tệp trên Linux. Vì vậy, cho một trường hợp đơn giản, khi một tập tin được đóng lại, sao chép nó vào một thư mục khác không hoạt động. –

2

Nếu bạn sẵn sàng tham gia một số tiền, JNIWrapper là 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ổ.

http://www.teamdev.com/jniwrapper/index.jsf

Nếu không, phải dùng đến mã nguồn gốc không phải lúc nào cũng là một điều xấu nhất là khi sản phẩm tốt nhất trên cung cấp là một cơ chế bỏ phiếu như chống lại một sự kiện tự nhiên .

Tôi đã nhận thấy rằng 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.

27

Có một lib được gọi là jnotify kết thúc tốt đẹp inotify trên Linux và cũng hỗ trợ cửa sổ. Không bao giờ sử dụng nó và tôi không biết nó tốt như thế nào, nhưng nó có giá trị một thử tôi muốn nói.

+1

Nó hoạt động hoàn hảo và siêu đơn giản để sử dụng. Tôi đã sử dụng inotify trong nhiều năm. Đó là nhanh chóng, ổn định và đáng tin cậy –

102

Tôi đã viết một tệp nhật ký theo dõi trước đây và tôi thấy rằng tác động đến hiệu suất hệ thống của việc bỏ phiếu 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ự rất nhỏ.

Java 7, như một phần của NIO.2 đã bổ sung API WatchService API

Các WatchService được thiết kế cho các ứng dụng cần phải được thông báo về các sự kiện thay đổi tập tin.

+7

tôi thấy các ví dụ như xem thư mục, nhưng những gì về một tập tin cá nhân? –

+0

@ArchimedesTrajano API thông báo cho bạn khi một tệp trong thư mục đã thay đổi. Sự kiện được kích hoạt bao gồm tên của tệp đã thay đổi. Vì vậy, bạn có thể xử lý các sự kiện cho một tệp hoặc tệp nhất định và bỏ qua những người khác. – Michael

+0

@ArchimedesTrajano https://stackoverflow.com/questions/16251273/can-i-watch-for-single-file-change-with-watchservice-not-the-whole-directory – user1742529

3

"Nhiều tính năng NIO" 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 có trong JDK7.

+0

Bạn có thể cụ thể hơn hoặc đăng liên kết không để tài liệu? Có vẻ như không tìm thấy bất cứ điều gì về điều này ... – Luciano

37

tôi sử dụng API VFS từ Apache Commons, đây là một ví dụ về làm thế nào để theo dõi một tập tin mà không ảnh hưởng nhiều trong hoạt động:

DefaultFileMonitor

+1

cảm ơn câu trả lời này!chính xác những gì tôi đã tìm kiếm… –

+0

rất hữu ích, cảm ơn –

1

Bạn cũng có thể xem xét Apache Commons JCI (Java Compiler Interface). 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ó để theo dõi các thay đổi của tệp.

Ví dụ: http://commons.apache.org/jci/usage.html

3

Tôi chạy đoạn mã này mỗi khi tôi đọc tệp thuộc tính, chỉ thực sự đọc tệp nếu tệp đã được sửa đổi kể từ lần cuối tôi đọc nó. Hy vọng điều này sẽ giúp một 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.

7

Java commons-io có FileAlterationObserver. nó sẽ bỏ phiếu kết hợp với một FileAlterationMonitor. Tương tự như VFS. Ưu điểm là nó có ít phụ thuộc hơn nhiều.

chỉnh sửa: Ít phụ thuộc không đúng, chúng là tùy chọn cho VFS. Nhưng nó sử dụng java File thay vì lớp trừu tượng VFS.

1

Bạn có thể nghe các thay đổi tệp bằng cách sử dụng Trình đọc tài liệu. Plz xem ví dụ dưới đây

// 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(); 
    } 
} 
0

Polling thuộc tính tập tin sửa đổi lần cuối là một giải pháp đơn giản nhưng hiệu quả mặc dù. Chỉ cần xác định một lớp mở rộng FileChangedWatcher của tôi và thực hiện các onModified() phương pháp:

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

Tương tự như các câu trả lời khác, dưới đây là cách tôi đã làm nó sử dụng File, Timer, và TimerTask để cho hoạt động này như một điểm bỏ phiếu sợi nền trong khoảng thời gian thiết lập .

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

    } 
} 
Các vấn đề liên quan