Избегайте обнаружения неполных файлов при просмотре каталога на наличие изменений в Java - PullRequest
8 голосов
/ 20 января 2011

Я просматриваю каталог для входящих файлов (используя FileAlterationObserver от Apache Commons).

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

Файлы записываются на месте процессами, которые я не могу контролировать.

Проблема с этим кодом заключается в том, что мой обратный вызов запускается при первоначальном создании файла.Мне нужно, чтобы он срабатывал, когда файл был изменен и запись в файл завершена.(может быть, обнаружив, когда файл перестал изменяться)

Какой лучший способ сделать это?

Ответы [ 5 ]

7 голосов
/ 10 мая 2012

У меня была похожая проблема. Сначала я подумал, что могу использовать службу 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());
2 голосов
/ 30 ноября 2015

Общее решение этой проблемы кажется невозможным со стороны «потребителя». «Производитель» может временно закрыть файл и затем возобновить добавление к нему. Или «производитель» может произойти сбой, оставив неполный файл в файловой системе.

Разумный шаблон - запись «производителем» во временный файл, который не отслеживается «потребителем». Когда запись закончится, переименуйте файл во что-то, что фактически отслеживается «потребителем», после чего «потребитель» подберет файл целиком.

1 голос
/ 20 января 2011

Вы можете проверить размер файла 2 или более раз за пару секунд, и если размер не меняется, то вы можете решить, что изменение файла завершено, и продолжить собственное выполнение.

1 голос
/ 20 января 2011

Я не думаю, что вы можете достичь того, чего хотите, если у вас нет ограничений и гарантий файловой системы.Например, что если у вас есть следующий сценарий:

  • Создан файл X
  • Запущено несколько событий изменения, соответствующих записи из файла X
  • Много времени проходит без обновлений файла X
  • Файл X обновляется.

Если файл X не может быть обновлен после его записи, вы можете иметь поток выполнения, которыйвычисляет время, прошедшее с момента последнего обновления до настоящего момента, и через некоторый интервал решает, что запись в файл завершена.Но даже у этого есть проблемы.Если файловая система зависла, и запись в течение некоторого времени не происходит, вы можете ошибочно заключить, что запись файла завершена.

0 голосов
/ 05 декабря 2014

Если вы используете FileAlterationListener и добавляете FileAltivationListenerAdaptor , вы можете реализовать необходимые методы и отслеживать файлы с помощью FileAltivationMonitor ...

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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...