2010-01-12 3 views
22

Как создать операцию записи атомарного файла? Файл должен быть написан службой Java и прочитан скриптами python.
Для записи чтение намного больше, чем пишет. Но запись происходит в партиях и, как правило, длинна. Размер файла составляет мегабайты.Операции записи на атомные файлы (кросс-платформа)

Сейчас мой подход:

  • содержимое файла в записи временный файл в том же каталоге
  • Удалить старый файл
  • Rename временный файл со старым именем.

Это правильный подход? Как избежать ситуаций, когда старый файл удален, но новое имя файла еще не переименовано?

Эти языки программирования (python и java) предлагают конструкции для блокировки и предотвращения этой ситуации?

+2

Замечание: похоже, что Java NIO.2 имеет лучшую поддержку для этого (по крайней мере, на уровне API): http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path .html # moveTo% 28java.nio.file.Path,% 20java.nio.file.CopyOption ...% 29 –

+0

Как и http://stackoverflow.com/questions/1812115/how-to-safely-write-to -a-file –

+0

@Pascal. Его в Java 7. Долгий путь ... :-( –

ответ

8

AFAIK no.

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

EDIT - Я ошибаюсь для систем, совместимых с POSIX, по крайней мере. Сценарий POSIX rename выполняет замену атома, если файл с целевым именем уже существует ... как указано @janneb. Этого должно быть достаточно, чтобы выполнить операцию OP атомарно.

Однако, факт остается факт, что метод Java File.renameTo()явно не гарантировано атомарным, поэтому он не обеспечивает кросс-платформенное решения проблемы операционной в.

EDIT 2 - С Java 7 вы можете использовать java.nio.file.Files.move(Path source, Path target, CopyOption... options) с copyOptions и ATOMIC_MOVE. Если это не поддерживается (операционной системой/файловой системой), вы должны получить исключение.

+1

+1: Ahhh, эти надоедливые различия ОС, препятствующие решению «кросс-платформы». –

+0

Настоящий ответ заключается в том, что вместо этого следует использовать блокировки файлов. – unixman83

+0

«И никто основной операционной системы предлагают транзакционную файловую систему. «Что? У NTFS была поддержка транзакций в течение длительного времени. http://msdn.microsoft.com/en-us/magazine/cc163388.aspx –

0

Попробуйте Java FileLock API

+1

Да ... но это не позволит вам заменить атомный файл. –

+1

Вы не полностью правы. С помощью этого api вы можете создать файл «.lock» и использовать его как семафор. Usecase: если файл заблокирован - python ждет, пока он не разблокируется, а затем начните читать (и файл блокировки) после чтения файла разблокировки. Когда служба нуждается в записи данных - проверьте, заблокирован ли файл, подождите, пока он не разблокируется, заблокирует его, запишет данные и разблокирует. –

+0

Во всяком случае, это эффективно ответ только для ссылок, и ссылка не объясняет, как решить вопрос OP. По сегодняшним меркам это низкий ответ. –

1

Вы можете попробовать и использовать дополнительный файл, чтобы действовать как замок, но я не уверен, что будет работать нормально. (Это заставит вас создать проверку блокировки и повторить логику с обеих сторон, java и python)

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

5

По крайней мере, на платформах POSIX оставьте шаг 3 (удалите старый файл). В POSIX переименование внутри файловой системы гарантированно будет атомарным, а переименование поверх существующего файла заменяет его атомарно.

1

Попросите сценарии python запросить разрешение у службы. Пока служба пишет, она помещает блокировку в файл. Если блокировка существует, служба отклонит запрос python.

3

Это классическая проблема производителя/потребителя.Вы должны решить эту проблему, используя переименование файлов, которое является атомарным в системах POSIX.

2

В Linux, Solaris, Unix это очень просто. Просто используйте rename() из вашей программы или mv. Файлы должны находиться в одной файловой системе.

В Windows это возможно, если вы можете управлять обеими программами. LockFileEx. Для чтения откройте файл блокировки shared lock. Для записи откройте файл блокировки exclusive lock. Блокировка странная в Windows, поэтому я рекомендую использовать отдельный файл блокировки .