Вопрос по java – Как проверить, является ли файл «полным» (полностью написанным) с помощью Java
Допустим, у вас есть внешний процесс, записывающий файлы в какой-либо каталог, и у вас был отдельный процесс, периодически пытающийся читать файлы из этого каталога. Проблема, которую следует избегать, - это чтение файла, который в данный момент находится в процессе записи другого процесса, поэтому он будет неполным. В настоящее время процесс, который читает, использует проверку таймера минимального срока хранения файлов, поэтому он игнорирует все файлы, если их дата последнего изменения не превышает XX секунд.
Мне интересно, есть ли более чистый способ решить эту проблему. Если тип файла неизвестен (может быть несколько различных форматов), существует ли какой-либо надежный способ проверить заголовок файла на количество байтов, которое должно быть в файле, против количества байтов, находящихся в данный момент в файле, для подтверждения их соответствия?
Спасибо за любые мысли или идеи!
tail
в Unix)
Peter Lawrey
2 варианта, которые, кажется, решают эту проблему:
- the best option- writer process notify reading process somehow that the writing was finished.
- 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.
Одно простое решение, которое я использовал в прошлом для этого сценария с Windows, заключается в использованииboolean File.renameTo(File)
и попытайтесь переместить исходный файл в отдельную промежуточную папку:
boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);
Еслиsuccess
являетсяfalse
тогдаpotentiallyIncompleteFile
все еще пишется.
Во-первых, естьПочему OS X не блокирует файлы, как Windows, при копировании на общий ресурс Samba? но это то, что вы уже делаете.
Что касается чтения произвольных файлов и поиска размеров, некоторые файлы содержат эту информацию, а некоторые - нет, но даже те, которые не имеют какого-либо общего способа ее представления. Вам потребуется конкретная информация о каждом формате и управлять ими независимо друг от друга.
Если вы абсолютно обязаны действовать в отношении файла, & quot; Мгновенно & quot; это сделано, тогда ваш процесс написания должен будет отправить какое-то уведомление. В противном случае вы в значительной степени застряли в опросе файлов, и чтение каталога довольно дешево с точки зрения ввода-вывода по сравнению со считыванием случайных блоков из случайных файлов.
Способ, которым я делал это в прошлом, заключается в том, что процесс записи файла записывает в «временный» файл. файл, а затем перемещает файл в место чтения, когда он закончил запись файла.
Таким образом, процесс записи будет писать вinfo.txt.tmp, Когда он закончен, он переименовывает файл вinfo.txt, Процесс чтения тогда просто нужно было проверить на наличиеinfo.txt - и он знает, что если он существует, он был написан полностью.
В качестве альтернативы вы можете записать процесс записиinfo.txt в другой каталог, а затем переместите его в каталог чтения, если вам не нравится использовать странные расширения файлов.
Вы можете использовать внешний файл маркера. Процесс записи может создать файл XYZ.lock до того, как он начнет создавать файл XYZ, и удалить XYZ.lock после завершения XYZ. Тогда читатель легко узнает, что он может считать файл завершенным, только если соответствующий файл .lock отсутствует.
lsof
делает) и проверьте, открыт ли файл. Но такой подход был бы взломан: утомителен для реализации и подвержен ошибкам.
Это можно сделать с помощью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);
У меня не было возможности использовать временные маркеры и т. Д., Так как файлы загружаются клиентами через 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.