繁体   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