在查看java中的更改目录时,请避免检测不完整的文件

lev*_*lex 9 java file-io

我正在查看传入文件的目录(使用来自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);
    }
}
Run Code Online (Sandbox Code Playgroud)

文件由我无法控制的进程写入.

我对该代码的问题是在最初创建文件时触发了我的回调.我需要它来在文件被更改并且对文件的写入完成时触发.(可能通过检测文件何时停止更改)

最好的方法是什么?

小智 7

我遇到了类似的问题.起初我以为我可以使用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());
Run Code Online (Sandbox Code Playgroud)


Ami*_*ani 1

我认为除非有一些文件系统约束和保证,否则您无法实现您想要的目标。例如,如果您有以下场景该怎么办:

  • 文件 X 已创建
  • 触发一系列与写出文件 X 相对应的更改事件
  • 很长时间过去了,文件 X 没有更新
  • 文件 X 已更新。

如果文件X在写出后无法更新,您可以有一个执行线程来计算从上次更新到现在经过的时间,并在一段时间间隔后决定文件写入完成。但即使这样也有问题。如果文件系统挂起,并且一段时间内没有进行写入,您可能会错误地认为文件已完成写出。