Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

  • лучший способ-писатель-процесс уведомляет процесс чтения так или иначе, что запись была закончена.
  • напишите файл на {id}.tmp, а затем, когда закончите - переименуйте его в {id}.java, и процесс чтения выполняется только в *.java файлах. переименование занимает гораздо меньше времени, и вероятность того, что этот процесс будет работать вместе, уменьшится.

Ответ 5

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

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

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

Ответ 6

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

boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);

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

Ответ 7

У меня не было возможности использовать временные маркеры и т.д., так как файлы загружаются клиентами через парную партию 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;
}

Ответ 8

Это можно сделать, используя Apache Commons IO maven library 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);