Проверка, полностью ли записан файл

В настоящее время я работаю над проектом, который обрабатывает файлы из исходного каталога в одной из его подпрограмм. Там есть процесс Java, который ищет указанный каталог и пытается читать и обрабатывать файлы, если они существуют. Файлы закрываются большими и обновляются другим процессом третьей стороны. Вопрос в том, как я могу проверить, полностью ли написан файл? Я пытаюсь использовать file.length(), но выглядит, даже если процесс записи не был завершен, он возвращает фактический размер. У меня такое чувство, что решение должно быть зависимым от платформы. Любая помощь будет оценена.

UPDATE: Этот вопрос не сильно отличается от дубликата, но у него есть ответ с хорошим фрагментом кода работы.

Ответы

Ответ 1

Завершает ли процесс продюсера файл при его завершении записи? Если это так, попытка открыть файл в потребительском процессе с исключительной блокировкой завершится неудачно, если процесс-производитель все еще производит.

Ответ 2

Я получил решение:

private boolean isCompletelyWritten(File file) {
    RandomAccessFile stream = null;
    try {
        stream = new RandomAccessFile(file, "rw");
        return true;
    } catch (Exception e) {
        log.info("Skipping file " + file.getName() + " for this iteration due it not completely written");
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                log.error("Exception during closing file " + file.getName());
            }
        }
    }
    return false;
}

Благодаря @cklab и @Will и всем остальным, которые предложили посмотреть "эксклюзивный замок". Я просто разместил код здесь, чтобы другие заинтересованы в том, чтобы люди его использовали. Я считаю, что решение с переименованием, предложенное @tigran, также работает, но для меня предпочтительным является чистое Java-решение.

P.S. Первоначально я использовал FileOutputStream вместо RandomAccessFile, но он блокировал записываемый файл.

Ответ 3

Я не думаю, что для этого существует общее решение. Поиск размера файла неверен, поскольку некоторые приложения могут устанавливать размер файла перед любым вызовом записи. Одна из возможностей - использовать блокировку. Это потребует, чтобы писатель набирал блокировку записи (или исключительную блокировку). Если вы не можете изменить автора, то вы можете использовать инструменты, предоставляемые ОС, например, фьюзер в Linux, чтобы увидеть, есть ли процесс, который все еще обращается к файлу.

Ответ 4

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

Другой подход заключается в том, чтобы один процесс записывал файл с именем, которое ваш процесс не распознает, а затем переименуйте файл в распознаваемое имя, когда запись будет завершена. На большинстве платформ операция переименования является атомарной, если источник и получатель имеют одинаковый объем файловой системы.

Ответ 5

Одним из простых решений, которые я использовал в прошлом для этого сценария в Windows, является использование boolean File.renameTo(File) и попытка переместить исходный файл в отдельную промежуточную папку:

boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);

Если success - false, то potentiallyIncompleteFile все еще записывается в.

Ответ 6

Если вы можете использовать Java 1.7, взгляните на инструменты NIO, в частности java.nio.channels.FileChannel

здесь является примером блокировки файла и его чтения.