簡體   English   中英

在查看java中的更改目錄時,請避免檢測不完整的文件

[英]Avoid detecting incomplete files when watching a directory for changes in java

我正在查看傳入文件的目錄(使用來自apache commons的FileAlterationObserver )。

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

文件由我無法控制的進程寫入。

我對該代碼的問題是在最初創建文件時觸發了我的回調。 我需要它來在文件被更改並且對文件的寫入完成時觸發。 (可能通過檢測文件何時停止更改)

最好的方法是什么?

我遇到了類似的問題。 起初我以為我可以使用FileWatcher服務,但它不能在遠程卷上運行,我必須通過網絡安裝的驅動器監視傳入的文件。

然后我想我可以簡單地監視一段時間內文件大小的變化,並在文件大小穩定后考慮文件完成(如fmucar建議的那樣)。 但我發現在大型文件的某些情況下,托管系統會報告它正在復制的文件的完整大小,而不是它寫入磁盤的字節數。 這當然使文件顯得穩定,我的探測器會在文件處於寫入過程中時捕獲文件。

我最終能夠通過使用FileInputStream異常使監視器工作,該異常在檢測文件是否被寫入時非常有效,即使文件位於網絡安裝的驅動器上也是如此。

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

從“消費者”端看來,這個問題的通用解決方案似乎是不可能的。 “生產者”可以暫時關閉該文件,然后繼續追加該文件。 或者“生產者”可能會崩潰,在文件系統中留下不完整的文件。

一個合理的模式是讓“生產者”寫入不受“消費者”監控的臨時文件。 完成寫入后,將文件重命名為“消費者”實際監控的內容,此時“消費者”將獲取完整的文件。

除非你有一些文件系統限制和保證,否則我認為你不能達到你想要的效果。 例如,如果您有以下情況怎么辦:

  • 文件X已創建
  • 觸發了一堆與寫出文件X相對應的更改事件
  • 很多時間都沒有更新到文件X.
  • 文件X已更新。

如果文件X在寫出后無法更新,則可以有一個執行線程來計算從上次更新到現在的經過時間,並在一段時間后確定文件寫入完成。 但即使這樣也有問題。 如果文件系統掛起,並且寫入沒有發生一段時間,您可能會錯誤地斷定文件已完成寫出。

您可以在幾秒鍾內檢查文件大小2次或更多次,如果大小沒有變化,則可以確定文件更改已完成並繼續執行。

如果您使用FileAlterationListener並添加FileAlterationListenerAdaptor你可以實現你需要的方法和監視與文件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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM