Как безопасно обновить файл, который имеет много читателей и одного писателя? - PullRequest
3 голосов
/ 07 января 2009

У меня есть набор файлов. Набор файлов доступен только для чтения из общей папки NTFS, поэтому может иметь много читателей. Каждый файл иногда обновляется одним автором, у которого есть права на запись.

Как мне убедиться, что:

  1. Если запись не удалась, предыдущий файл все еще доступен для чтения
  2. Читатели не могут задержать одного писателя

Я использую Java, и мое текущее решение для писателя - записать во временный файл, а затем заменить его на существующий файл, используя File.renameTo(). Проблема в NTFS, renameTo завершается ошибкой, если целевой файл уже существует, поэтому вы должны удалить его самостоятельно. Но если средство записи удаляет целевой файл, а затем выходит из строя (сбой компьютера), у меня нет читаемого файла.

FileLock nio работает только с той же JVM, поэтому для меня это бесполезно.

Как безопасно обновить файл многими читателями, используя Java?

Ответы [ 6 ]

3 голосов
/ 07 января 2009

Согласно JavaDoc :

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

1 голос
/ 07 января 2009

То, что всегда должно работать, независимо от того, какая ОС и т. Д., Меняет программное обеспечение вашего клиента.

Если это опция, у вас может быть файл "settings1.ini", и если вы хотите его изменить, вы создаете файл "settings2.ini.wait", затем записываете свои данные в него и затем переименовываете его в "settings2.ini", а затем удалите "settings1.ini".

Ваше измененное клиентское программное обеспечение будет просто всегда проверять наличие settings2.ini, если оно в последний раз прочитало settings1.ini, и наоборот.

Таким образом, у вас всегда есть рабочая копия.

1 голос
/ 07 января 2009

В системе Unix я бы удалил файл и затем открыл его для записи. Любой, у кого она открыта для чтения, все равно увидит старую, и как только они закроют ее, она исчезнет из файловой системы. Я не знаю, имеет ли NTFS схожую семантику, хотя я слышал, что она в значительной степени основана на файловой системе BSD, поэтому, возможно, это так.

1 голос
/ 07 января 2009

Я не знаю, применимо ли это, но если вы работаете в чистом решении Vista / Windows Server 2008, я бы использовал TxF (транзакционную NTFS), а затем убедился, что вы открываете дескриптор файла и выполняете операции с файлами вызывая соответствующие файловые API через JNI.

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

0 голосов
/ 07 января 2009

Возможно, нет необходимости в блокировке. Я не слишком знаком с API FS в Windows, но поскольку NTFS поддерживает как жесткие, так и программные ссылки AFAIK, вы можете попробовать это, если ваша настройка позволяет:

Используйте жесткую или программную ссылку, чтобы указать на фактический файл, и назовите файл по-другому. Разрешить всем доступ к файлу по имени ссылки.

Запишите новый файл под другим именем, в ту же папку.

Когда он закончится, укажите файлу новый файл. Оптимально, Windows позволит вам создать новую ссылку с заменой существующей ссылки в одной атомарной операции. Тогда у вас будет ссылка, которая всегда идентифицирует действительный файл, старый или новый. В худшем случае вам придется сначала удалить старый файл, а затем создать ссылку на новый файл. В этом случае будет короткий промежуток времени, в течение которого программа не сможет найти файл. (Кроме того, Mac OS X предлагает функцию «ExchangeObjects», которая позволяет атомарно менять два элемента - возможно, Windows предлагает что-то похожее).

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

Однако я не знаю, как создавать ссылки в Java. Может быть, вам придется использовать какой-то нативный API для этого.

Надеюсь, это поможет в любом случае.

0 голосов
/ 07 января 2009

Я недавно имел дело с чем-то похожим. Если вы используете Java 5, возможно, вы могли бы рассмотреть возможность использования блокировок файлов NIO в сочетании с ReentrantReadWriteLock? Убедитесь, что весь код, ссылающийся на объект FileChannel, ТАКЖЕ ссылается на ReentrantReadWriteLock. Таким образом, NIO блокирует его на уровне виртуальной машины, в то время как повторяющаяся блокировка блокирует его на уровне потока.

FileLock fileLock = filechannel.lock(position, size, shared);
reentrantReadWriteLock.lock();

// do stuff

fileLock.release();
reentrantReadWriteLock.unlock();

Конечно, потребуется некоторая обработка исключений.

...