Вопрос по java – Как проверить, является ли файл «полным» (полностью написанным) с помощью Java

24

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

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

Спасибо за любые мысли или идеи!

Есть ли у вас контроль над процессом записи файлов в каталог, который вы просматриваете? Simon Nickerson
Помимо переименования файла, когда я закончу, подход, который я использую, состоит в том, чтобы сделать его нормальным для чтения файла во время его записи (подумайтеtail в Unix) Peter Lawrey

Ваш Ответ

8   ответов
2

2 варианта, которые, кажется, решают эту проблему:

  1. the best option- writer process notify reading process somehow that the writing was finished.
  2. write the file to {id}.tmp, than when finish- rename it to {id}.java, and the reading process run only on *.java files. renaming taking much less time and the chance this 2 process work together decrease.
4

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

boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);

Еслиsuccess являетсяfalseтогдаpotentiallyIncompleteFile все еще пишется.

2

Во-первых, естьПочему OS X не блокирует файлы, как Windows, при копировании на общий ресурс Samba? но это то, что вы уже делаете.

Что касается чтения произвольных файлов и поиска размеров, некоторые файлы содержат эту информацию, а некоторые - нет, но даже те, которые не имеют какого-либо общего способа ее представления. Вам потребуется конкретная информация о каждом формате и управлять ими независимо друг от друга.

Если вы абсолютно обязаны действовать в отношении файла, & quot; Мгновенно & quot; это сделано, тогда ваш процесс написания должен будет отправить какое-то уведомление. В противном случае вы в значительной степени застряли в опросе файлов, и чтение каталога довольно дешево с точки зрения ввода-вывода по сравнению со считыванием случайных блоков из случайных файлов.

10

Способ, которым я делал это в прошлом, заключается в том, что процесс записи файла записывает в «временный» файл. файл, а затем перемещает файл в место чтения, когда он закончил запись файла.

Таким образом, процесс записи будет писать вinfo.txt.tmp, Когда он закончен, он переименовывает файл вinfo.txt, Процесс чтения тогда просто нужно было проверить на наличиеinfo.txt - и он знает, что если он существует, он был написан полностью.

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

10

Вы можете использовать внешний файл маркера. Процесс записи может создать файл XYZ.lock до того, как он начнет создавать файл XYZ, и удалить XYZ.lock после завершения XYZ. Тогда читатель легко узнает, что он может считать файл завершенным, только если соответствующий файл .lock отсутствует.

Не могли бы вы написать пример, который будет иллюстрировать процедуру?
Что если у вас нет контроля над процессом записи?
Здесь нет никаких дополнительных блокировок файла - факт, что файл существует или нет, является тем, что составляет блокировку.
Привет, Михал, как мы можем проверить, что & quot; файл заблокирован & quot; через программу.
@Matthieu Если вы не знаете подробностей о том, как выполняется запись, и не имеете контроля над автором, вы не можете многое гарантировать. Если вам известны некоторые детали, например, что файл открывается ровно один раз для записи, а затем закрывается, вы можете получить информацию из ОС об открытых файлах (например,lsof делает) и проверьте, открыт ли файл. Но такой подход был бы взломан: утомителен для реализации и подвержен ошибкам.
2

Это можно сделать с помощьюApache Commons IO библиотека maven FileUtils.copyFile () метод. Если вы попытаетесь скопировать файл и получить IOException, это означает, что файл сохранен не полностью.

Пример:

public static void copyAndDeleteFile(File file, String destinationFile) {

    try {
        FileUtils.copyFile(file, new File(fileDirectory));
    } catch (IOException e) {
        e.printStackTrace();
        copyAndDeleteFile(file, fileDirectory, delayThreadPeriod);
    }

Или периодически проверяйте с некоторой задержкой размер папки, содержащей этот файл:

FileUtils.sizeOfDirectory(folder);
Интересно, как Commons IO может отследить это. Так что это, вероятно, ответит на оригинальный вопрос без сложной копии раньше.
5

У меня не было возможности использовать временные маркеры и т. Д., Так как файлы загружаются клиентами через SFTP пары ключей. они могут быть очень большими по размеру.

Это довольно странно, но я сравниваю размер файла до и после нескольких секунд сна.

Очевидно, что он не идеален для блокировки потока, но в нашем случае он просто работает как фоновые системные процессы, поэтому, кажется, работает нормально

private boolean isCompletelyWritten(File file) throws InterruptedException{
    Long fileSizeBefore = file.length();
    Thread.sleep(3000);
    Long fileSizeAfter = file.length();

    System.out.println("comparing file size " + fileSizeBefore + " with " + fileSizeAfter);

    if (fileSizeBefore.equals(fileSizeAfter)) {
        return true;
    }
    return false;
}

Примечание: как упомянуто ниже, это может не работать на окнах. Это использовалось в среде Linux.

Единственной точкой отказа будет сбой сети
Этот код потерпит неудачу, так как метаданные размера файла записываются как первый шаг в Windows. Так что всегда file.length () один и тот же
В Mac это работает для небольших файлов и папок. Для больших файлов вместо длины я использовал размер файла и работает нормально.
2

Даже если количество байтов одинаково, содержимое файла может отличаться.

Поэтому я думаю, вы должны сопоставлять старый и новый файл побайтно.

Похожие вопросы