Ответ 1
Завершает ли процесс продюсера файл при его завершении записи? Если это так, попытка открыть файл в потребительском процессе с исключительной блокировкой завершится неудачно, если процесс-производитель все еще производит.
В настоящее время я работаю над проектом, который обрабатывает файлы из исходного каталога в одной из его подпрограмм. Там есть процесс Java, который ищет указанный каталог и пытается читать и обрабатывать файлы, если они существуют. Файлы закрываются большими и обновляются другим процессом третьей стороны. Вопрос в том, как я могу проверить, полностью ли написан файл? Я пытаюсь использовать file.length()
, но выглядит, даже если процесс записи не был завершен, он возвращает фактический размер. У меня такое чувство, что решение должно быть зависимым от платформы. Любая помощь будет оценена.
UPDATE: Этот вопрос не сильно отличается от дубликата, но у него есть ответ с хорошим фрагментом кода работы.
Завершает ли процесс продюсера файл при его завершении записи? Если это так, попытка открыть файл в потребительском процессе с исключительной блокировкой завершится неудачно, если процесс-производитель все еще производит.
Я получил решение:
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
, но он блокировал записываемый файл.
Я не думаю, что для этого существует общее решение. Поиск размера файла неверен, поскольку некоторые приложения могут устанавливать размер файла перед любым вызовом записи. Одна из возможностей - использовать блокировку. Это потребует, чтобы писатель набирал блокировку записи (или исключительную блокировку). Если вы не можете изменить автора, то вы можете использовать инструменты, предоставляемые ОС, например, фьюзер в Linux, чтобы увидеть, есть ли процесс, который все еще обращается к файлу.
Если вы планируете использовать этот код на одной платформе, вы можете использовать средство NIO FileLock. Но внимательно прочитайте документацию и обратите внимание, что на многих платформах блокировка является только рекомендательной.
Другой подход заключается в том, чтобы один процесс записывал файл с именем, которое ваш процесс не распознает, а затем переименуйте файл в распознаваемое имя, когда запись будет завершена. На большинстве платформ операция переименования является атомарной, если источник и получатель имеют одинаковый объем файловой системы.
Одним из простых решений, которые я использовал в прошлом для этого сценария в Windows, является использование boolean File.renameTo(File)
и попытка переместить исходный файл в отдельную промежуточную папку:
boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);
Если success
- false
, то potentiallyIncompleteFile
все еще записывается в.
Если вы можете использовать Java 1.7, взгляните на инструменты NIO, в частности java.nio.channels.FileChannel
здесь является примером блокировки файла и его чтения.