Вопрос

У меня есть небольшой код Java, который выводит XML-файл в смонтированную файловую систему NFS.На другом сервере, файловая система которого смонтирована как общий ресурс Samba, выполняется процесс, который опрашивает новые XML-файлы каждые 30 секунд.Если обнаружен новый файл, он обрабатывается, а затем переименовывается в файл резервной копии.В 99% случаев файлы записываются без проблем.Однако время от времени файл резервной копии содержит частично записанный файл.

После некоторого обсуждения с другими людьми мы предположили, что процесс, работающий на внешнем сервере, мешает выходному потоку Java при чтении файла.Они предложили сначала создать файл типа .temp, который затем будет переименован в .xml после завершения записи файла.Обычная отраслевая практика.После изменения переименование каждый раз завершается с ошибкой.

Некоторые исследования показали, что ввод-вывод файлов Java работает с ошибками при работе с файловыми системами, смонтированными по NFS.

Помогите мне, гуру Java!Как мне решить эту проблему?

Вот некоторая актуальная информация:

  • Мой процесс — Java 1.6.0_16, работающий на Solaris 10.
  • Подключенная файловая система — NAS.
  • Сервер с процессом опроса — Windows Server 2003 R2 Standard, пакет обновления 2.

Вот пример моего кода:

//Write the file
XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat());
FileOutputStream os = new FileOutputStream(outputDirectory + fileName + ".temp");
serializer.output(doc, os);//doc is a constructed xml document using JDOM
os.flush();
os.close();

//Rename the file
File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");
boolean success = oldFile.renameTo(newFile);
if (!success) {
    // File was not successfully renamed.
    throw new IOException("The file " + fileName + ".temp could not be renamed.");
}//if
Это было полезно?

Решение

Вероятно, вам придется указать полный путь в новом имени файла:

File newFile = new File(outputDirectory + fileName + ".xml");

Другие советы

Мне это кажется ошибкой:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");

Я ожидал этого:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(outputDirectory + fileName + ".xml");

В общем, похоже, что между записью XML-файла и задачей чтения/обработки/переименования существует состояние гонки.Можете ли вы выполнить задачу чтения/обработки/переименования только для файлов старше 1 минуты или чего-то подобного?

Или попросите программу Java записать дополнительный пустой файл после завершения записи XML-файла, который сигнализирует о завершении записи в XML-файл.Читайте/обрабатывайте/переименовывайте XML-файл только при наличии сигнального файла.Затем удалите файл сигнала.

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

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

РЕДАКТИРОВАТЬ:или проверьте временные метки, как указано выше, чтобы проверить это, но убедитесь, что они достаточно старые, чтобы любая неточность в временной метке не имела значения (скажем, от 10 секунд до 1 минуты с момента последнего изменения).

Альтернативно попробуйте следующее:

File f = new File("foo.xml");
FileOutputStream fos = new FileOutputStream(f);
FileChannel fc = fos.getChannel();
FileLock lock = fc.lock();
(DO FILE WRITE)
fis.flush();
lock.release();
fos.close();

При этом СЛЕДУЕТ использовать встроенную блокировку файлов ОС, чтобы предотвратить одновременный доступ других программ (например, демона чтения XML).

Что касается глюков NFS:существует документированная «функция» (ошибка), при которой файлы нельзя перемещать между файловыми системами посредством «переименования» в Java.Может ли быть путаница, поскольку он находится в файловой системе NFS?

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

Я видел эффекты, когда вы создавали файл, добавляли данные (это было видно на другой машине), но все данные после этого появлялись с задержкой в ​​30 секунд.

Кстати, лучшее решение — вращающаяся файловая схема.Таким образом, предполагается, что последний записан, а предыдущий был безопасно записан и может быть прочитан.Я бы не стал работать над одним файлом и использовать его как «трубу».

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

Возможно, из-за того, что «Операция переименования не может переместить файл из одной файловой системы в другую» из http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#renameTo%28java.io.File%2) Попробуйте использовать Apache Commons io filtutils.copyfiletodirectory http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#copyFileToDirectory(java.io.File,%20java.io.File) вместо

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top