2011-01-19 34 views
7

Tôi đang xem thư mục cho tệp đến (sử dụng FileAlterationObserver từ dấu phẩy apache).Tránh phát hiện tệp không đầy đủ khi xem thư mục để thay đổi trong java

class Example implements FileAlterationListener { 
    public void prepare() { 
     File directory = new File("/tmp/incoming"); 
     FileAlterationObserver observer = new FileAlterationObserver(directory); 
     observer.addListener(this); 
     FileAlterationMonitor monitor = new FileAlterationMonitor(10); 
     monitor.addObserver(observer); 
     monitor.start(); 
     // ... 
    } 

    public void handleFile(File f) { 
     // FIXME: this should be called when the writes that 
     // created the file have completed, not before 
    } 

    public void onFileCreate(File f) { 
     handleFile(f); 
    } 

    public void onFileChange(File f) { 
     handleFile(f); 
    } 
} 

Các tệp được viết bằng các quy trình mà tôi không kiểm soát.

Sự cố tôi gặp phải với mã đó là cuộc gọi lại của tôi được kích hoạt khi Tệp được tạo ban đầu. Tôi cần nó để kích hoạt khi tập tin đã được thay đổi và ghi vào tập tin đã hoàn thành. (có thể bằng cách phát hiện khi tệp dừng lại thay đổi)

Cách tốt nhất để làm điều đó là gì?

+0

IOW bạn muốn biết khi nào quá trình ghi đóng tệp? – finnw

+0

Tôi nghĩ rằng về cơ bản tôi cần triển khai [debounce] (http://documentcloud.github.com/underscore/docs/underscore.html#section-52) để Java – levinalex

+0

đóng lại tệp: Có, nếu tác vụ đó có thể giải quyết nó. (Có cách nào để lấy thông tin đó mà không có bất kỳ sự kiểm soát nào đối với người viết không?) Tôi có thể thử lấy một khóa độc quyền trên tập tin không? Điều đó có hoạt động trên các nền tảng không? – levinalex

Trả lời

1

Tôi không nghĩ rằng bạn có thể đạt được những gì bạn muốn trừ khi bạn có một số hạn chế hệ thống tập tin và đảm bảo. Ví dụ, nếu bạn có các tình huống sau:

  • file X tạo
  • Một loạt các sự kiện thay đổi được kích hoạt tương ứng với văn bản ra khỏi tập tin X
  • Rất nhiều thời gian trôi qua không có bản cập nhật cho file X
  • File X được cập nhật.

Nếu tệp X không thể cập nhật sau khi nó được viết ra, bạn có thể thực hiện một chuỗi thực hiện tính toán thời gian đã trôi qua từ lần cập nhật cuối cùng đến giờ và sau một khoảng thời gian. Nhưng ngay cả điều này cũng có vấn đề. Nếu hệ thống tập tin bị treo, và quá trình ghi không xảy ra trong một thời gian, bạn có thể kết luận sai rằng tập tin đã được viết xong.

+1

Bạn nói đúng. Nhưng may mắn thay điều này không xảy ra trong trường hợp của tôi. (Các bước 1 đến 3 xảy ra, Bước 4 không) Tệp được ghi vào _reasonably quick_ – levinalex

+0

Trong trường hợp đó, bạn có thể làm những gì tôi đã nói. Vẫn có những hạn chế đối với phương pháp này. Đối với một, bạn sẽ cần một chủ đề cho mỗi tập tin. Khác, là chọn một giá trị heuristic cho thời gian trôi qua. –

+0

Vâng. Tôi đã thực hiện một câu hỏi followup [Debounce in Java] (http://stackoverflow.com/questions/4742210/implementing-debounce-in-java) cho giải pháp thread. (_reasonably quickly_ là 100ms trong trường hợp của tôi) Tôi thực sự quan tâm nếu cách tiếp cận khóa sẽ làm việc vì đó sẽ là rất nhiều thanh lịch hơn. – levinalex

1

Bạn có thể kiểm tra kích thước của tệp 2 lần trở lên sau một vài giây và nếu kích thước không thay đổi, bạn có thể quyết định thay đổi tệp đã hoàn thành và tiếp tục thực hiện.

7

Tôi gặp sự cố tương tự. Lúc đầu, tôi nghĩ rằng tôi có thể sử dụng dịch vụ FileWatcher, nhưng nó không hoạt động trên khối lượng từ xa, và tôi đã phải theo dõi các tập tin đến thông qua một ổ đĩa gắn trên mạng. Sau đó, tôi nghĩ rằng tôi có thể chỉ cần theo dõi sự thay đổi kích thước tập tin trong một khoảng thời gian và xem xét các tập tin được thực hiện một khi kích thước tập tin đã ổn định (như fmucar đề nghị). Nhưng tôi thấy rằng trong một số trường hợp trên các tệp lớn, hệ thống lưu trữ sẽ báo cáo kích thước đầy đủ của tệp mà nó đã sao chép, thay vì số byte đã ghi vào đĩa. Điều này tất nhiên làm cho các tập tin xuất hiện ổn định, và phát hiện của tôi sẽ bắt các tập tin trong khi nó vẫn còn trong quá trình được viết.

Cuối cùng tôi có thể làm cho màn hình hoạt động, bằng cách sử dụng ngoại lệ FileInputStream, hoạt động tuyệt vời trong việc phát hiện xem tệp có được ghi vào hay không, ngay cả khi tệp nằm trên ổ đĩa được gắn mạng.

 long oldSize = 0L; 
     long newSize = 1L; 
     boolean fileIsOpen = true; 

     while((newSize > oldSize) || fileIsOpen){ 
      oldSize = this.thread_currentFile.length(); 
      try { 
      Thread.sleep(2000); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 
      newSize = this.thread_currentFile.length(); 

      try{ 
       new FileInputStream(this.thread_currentFile); 
       fileIsOpen = false; 
      }catch(Exception e){} 
     } 

     System.out.println("New file: " + this.thread_currentFile.toString()); 
+0

Vậy tại sao vẫn kiểm tra kích thước? Tại sao không chỉ kiểm tra xem nó có mở không? – Steve

+0

Tôi nghĩ tốt hơn là không nên sử dụng một FileInputStream ẩn danh, vì vậy bạn có thể đóng nó sau vòng lặp. Nếu không, mặc dù điều này làm việc tuyệt vời cho tôi! – Steve

0

Nếu bạn sử dụng FileAlterationListener và thêm một FileAlterationListenerAdaptor bạn có thể thực hiện các phương pháp bạn cần và theo dõi các tập tin với một FileAlterationMonitor ...

public static void main(String[] args) throws Exception { 

    FileAlterationObserver fao = new FileAlterationObserver(dir); 
    final long interval = 500; 
    FileAlterationMonitor monitor = new FileAlterationMonitor(interval); 
    FileAlterationListener listener = new FileAlterationListenerAdaptor() { 

     @Override 
     public void onFileCreate(File file) { 
      try { 
       System.out.println("File created: " + file.getCanonicalPath()); 
      } catch(IOException e) { 
       e.printStackTrace(System.err); 
      } 
     } 

     @Override 
     public void onFileDelete(File file) { 
      try { 
       System.out.println("File removed: " + file.getCanonicalPath()); 
      } catch(IOException e) { 
       e.printStackTrace(System.err); 
      } 
     } 

     @Override 
     public void onFileChange(File file) { 
      try { 
       System.out.println(file.getName() + " changed: "); 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 
    // Add listeners... 
    fao.addListener(listener); 
    monitor.addObserver(fao); 
    monitor.start(); 
} 
+0

hi, đây là cách làm thế nào để thực hiện thay đổi tập tin, nhưng nó không xử lý trường hợp khi khoảng thời gian bỏ phiếu ít hơn thời gian cần thiết để sao chép toàn bộ tập tin từ một vị trí mạng khác. Tôi đã thấy vấn đề này trong mã của chúng tôi, vì vậy cần phải thực hiện một số kiểm tra bổ sung hoặc vòng lặp chờ cho tệp đang được kích hoạt bởi hệ thống tệp, sau đó chuyển sang bộ điều hợp, bộ điều hợp cần đợi cho đến khi tệp hoàn tất. –

2

Một giải pháp chung cho vấn đề này dường như không thể từ " người tiêu dùng "kết thúc. "Nhà sản xuất" có thể tạm thời đóng tệp và sau đó tiếp tục thêm vào tệp đó. Hoặc "nhà sản xuất" có thể sụp đổ, để lại một tệp không đầy đủ trong hệ thống tệp.

Mẫu hợp lý là để "nhà sản xuất" ghi vào tệp tạm thời không được người tiêu dùng giám sát. Khi nó được thực hiện bằng văn bản, đổi tên tập tin vào một cái gì đó mà thực sự theo dõi bởi "người tiêu dùng", tại thời điểm đó "người tiêu dùng" sẽ nhận tập tin hoàn chỉnh.

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