Trình nghe đã thay đổi tệp trong Java


104

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ảm ơn vì tất cả những phản hồi. Vì nhu cầu của tôi là nhỏ (tôi chỉ cần tải lại một tệp thuộc tính đã thay đổi trong ứng dụng web của mình..chủ yếu là do việc khởi động lại toàn bộ ứng dụng web hơi chậm), tôi sẽ tiếp tục gắn bó với 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 luận án.
cheng81

14
Chỉ là một ghi chú. Khi chúng tôi giải quyết vấn đề này trước khi chúng tôi nhận thấy rằng các tệp lớn có xu hướng đến chậm và cơ chế thăm dò thường phát hiện ra một tệp mới hoặc đã thay đổi trước khi nó được ghi đầy đủ. Để giải quyết vấn đề này, một giải pháp 'hai miếng' đã được áp dụng. Người thăm dò nhận thấy một tệp đã thay đổi, nhưng không thông báo cho hệ thống về một tệp 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 rất nhiều lỗi badfile.
Steve Powell

1
Ngoài ra, Tomcat gặp phải vấn đề đó khi thả các tệp WAR lớn vào thư mục ứng dụng web từ các nguồn từ xa và đã làm như vậy trong một thời gian dài.
John Rix,

Câu trả lời:


21

Ở 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ở.


59
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 dịch vụ thông báo của hệ điều hành: blogs.oracle.com/thejavatutorials/entry/...
Arnout Engelen

API đó rất thiếu sót, 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, với một trường hợp đơn giản, khi một tệp được đóng, sao chép nó vào thư mục khác không hoạt động.
binarytemple_picsolve

117

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.


10
Tôi xem các ví dụ là thư mục đang xem, nhưng còn một tệp riêng lẻ thì sao?
Archimedes Trajano,

@ArchimedesTrajano API sẽ thông báo cho bạn khi 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 các tệp nhất định và bỏ qua những tệp khác.
Michael



27

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.


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. Nó nhanh, ổn định và đáng tin cậy
oᴉɹǝɥɔ

8

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.


4

"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.


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

Nó có vẻ là gói java.nio.file. Xem một hướng dẫn .
David L.

4

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.


2

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

2

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.


1

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.

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




1

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 FileChangedWatchervà 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();
}

0

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

  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.