Транзакционное открытие / запись / замена в .NET? - PullRequest
4 голосов
/ 24 сентября 2011

Я думаю, может быть, я должен ограничить его до 8 КБ. Я хотел бы открыть файл и писать от начала до конца каждый раз. Однако, если по какой-либо причине (скажем, отключение питания) он не завершен, я не хочу поврежденных данных. Есть ли способ, которым я могу сделать транзакционный файл открывать / писать / закрывать, чтобы он не заменил предыдущий файл, если он не был успешным?

Когда я Google, я получаю много результатов по транзакциям базы данных и ado вместо файлов

Ответы [ 3 ]

3 голосов
/ 24 сентября 2011
  1. Запись во временный файл,
  2. Удаление старого файла
  3. Переименование временного файла только в случае успешной записи.

Для предотвращения данныхпотеря при сбое питания после второго шага, но перед третьим шагом вам потребуется еще один шаг:

  • При запуске программы проверьте временные файлы, основные файлы которых удалены, но еще не переименованы.Если вы найдете что-либо, выполните шаг три снова для этих файлов.
2 голосов
/ 24 сентября 2011

NTFS в Windows Vista и более поздних версиях является транзакционной.

Я не верю, что вы можете получить к ней доступ из чистого управляемого кода - вам потребуется P / Invoke в Win32 API.* Хорошее место для начала: CreateTransaction, CommitTransaction, RollbackTransaction, CreateFileTransacted (и другие *Transacted) функции Win32 API.

1 голос
/ 24 сентября 2011

Небольшое отклонение от решения Марка Байера, которое я использую постоянно:

  1. Записать новое содержимое во временный файл в том же каталоге, как файл, который вы хотите заменить.
  2. Если запись прошла успешно, переименуйте [1] в нужный файл.

Переименование является атомарным, поэтому в случае успеха система не остается в неопределенном состоянии. Если происходит сбой, то, опять же, система все еще находится в первоначальном состоянии И , у вас есть резервная копия содержимого, которое вы хотели заменить (во временном файле) при перезагрузке системы.

Мое типичное соглашение об именах выглядит следующим образом:

/ путь / к / оригинал / content.data

/ путь / к / оригинальный /.# content.data

Если система выключается где-то в этом процессе, при перезапуске вашего приложения вы можете выполнить сканирование. # Content.data и либо представить его пользователю как то, что он вводил при выходе из системы, либо использовать какой-либо пользовательский Волшебство, чтобы решить, является ли это "полным", чтобы решить, стоит ли переименовать его через content.data.

Я не знаю, какие данные вы пишете, поэтому я не могу помочь вам решить, какой будет эта «магия», но если, например, это xml-файл, вы можете проанализировать его на предмет корректности, и если вы не получите неожиданный конец файла, тогда, возможно, у вас есть полный файл.

FWIW, ограничение себя записью 8k не спасет вас, потому что вы теперь зависите от деталей реализации в базовой ОС и FS, которые могут измениться в следующей версии или отличаться в предыдущей версии.

Ссылки:

  1. http://83.139.107.116:8080/1.1/handlers/monodoc.ashx?link=M%3aMono.Unix.Native.Stdlib.rename(System.String%2cSystem.String)
...