简体   繁体   English

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

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

I am watching a directory for incoming files (using FileAlterationObserver from apache commons). 我正在查看传入文件的目录(使用来自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);
    }
}

The files are written in place by processes that I have no control over. 文件由我无法控制的进程写入。

The problem I have with that code is that my callback is triggered when the File is initially created. 我对该代码的问题是在最初创建文件时触发了我的回调。 I need it to trigger when the file has been changed and the write to the file has completed. 我需要它来在文件被更改并且对文件的写入完成时触发。 (maybe by detecting when the file stopped changing) (可能通过检测文件何时停止更改)

What's the best way to do that? 最好的方法是什么?

I had a similar problem. 我遇到了类似的问题。 At first I thought I could use the FileWatcher service, but it doesn't work on remote volumes, and I had to monitor incoming files via a network mounted drive. 起初我以为我可以使用FileWatcher服务,但它不能在远程卷上运行,我必须通过网络安装的驱动器监视传入的文件。

Then I thought I could simply monitor the change in file size over a period of time and consider the file done once the file size had stabilized (as fmucar suggested). 然后我想我可以简单地监视一段时间内文件大小的变化,并在文件大小稳定后考虑文件完成(如fmucar建议的那样)。 But I found that in some instances on large files, the hosting system would report the full size of the file it was copying, rather than the number of bytes it had written to disk. 但我发现在大型文件的某些情况下,托管系统会报告它正在复制的文件的完整大小,而不是它写入磁盘的字节数。 This of course made the file appear stable, and my detector would catch the file while it was still in the process of being written. 这当然使文件显得稳定,我的探测器会在文件处于写入过程中时捕获文件。

I eventually was able to get the monitor to work, by employing a FileInputStream exception, which worked wonderfully in detecting whether a file was being written to, even when the file was on a network mounted drive. 我最终能够通过使用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());

A generic solution to this problem seems impossible from the "consumer" end. 从“消费者”端看来,这个问题的通用解决方案似乎是不可能的。 The "producer" may temporarily close the file and then resume appending to it. “生产者”可以暂时关闭该文件,然后继续追加该文件。 Or the "producer" may crash, leaving an incomplete file in the file system. 或者“生产者”可能会崩溃,在文件系统中留下不完整的文件。

A reasonable pattern is to have the "producer" write to a temp file that's not monitored by the "consumer". 一个合理的模式是让“生产者”写入不受“消费者”监控的临时文件。 When it's done writing, rename the file to something that's actually monitored by the "consumer", at which point the "consumer" will pick up the complete file. 完成写入后,将文件重命名为“消费者”实际监控的内容,此时“消费者”将获取完整的文件。

I don't think you can achieve what you want unless you have some file system constraints and guarantees. 除非你有一些文件系统限制和保证,否则我认为你不能达到你想要的效果。 For example, what if you have the following scenario : 例如,如果您有以下情况怎么办:

  • File X created 文件X已创建
  • A bunch of change events are triggered that correspond with writing out of file X 触发了一堆与写出文件X相对应的更改事件
  • A lot of time passes with no updates to file X 很多时间都没有更新到文件X.
  • File X is updated. 文件X已更新。

If file X cannot be updated after it's written out, you can have a thread of execution that calculates the elapsed time from the last update to now, and after some interval decides that the file write is complete. 如果文件X在写出后无法更新,则可以有一个执行线程来计算从上次更新到现在的经过时间,并在一段时间后确定文件写入完成。 But even this has issues. 但即使这样也有问题。 If the file system is hung, and the write does not occur for some time, you could erroneously conclude that the file is finished writing out. 如果文件系统挂起,并且写入没有发生一段时间,您可能会错误地断定文件已完成写出。

您可以在几秒钟内检查文件大小2次或更多次,如果大小没有变化,则可以确定文件更改已完成并继续执行。

If you use FileAlterationListener and add a FileAlterationListenerAdaptor you can implement the methods you need and monitor the files with a FileAlterationMonitor ... 如果您使用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