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

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

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

Чтобы еще больше усложнить ситуацию, для автоматического сохранения документа мне нужно сохранить один файл .xml и несколько файлов .png.Кроме того, сохранение .png происходит в коде C через JNI.

Моя текущая стратегия - записать каждый файл .png с расширением .png.tmp, записать файл .xml с расширением .xml.tmp изатем переименуйте каждый файл, чтобы удалить часть .tmp, оставляя .xml до последнего.При запуске я загружаю автосохраненный документ только в том случае, если могу найти файл .xml и игнорировать файлы .xml.tmp.Я также не удаляю предыдущий автосохраненный документ до тех пор, пока файл .xml.tmp для нового документа не будет переименован.

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

Ответы [ 2 ]

7 голосов
/ 07 ноября 2010

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

Чтобы предотвратить потерю данных из-за частично записанного файла автосохранения, не перезаписывайте автосохранениефайл.Вместо этого каждый раз записывайте в новый файл, а затем переименовывайте его, как только файл был благополучно записан.

Чтобы не замечать, что файл автосохранения записан неправильно:

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

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

СЛЕДОВАТЬ ВВЕРХ

Нет.Я не говорю, что переименовать всегда удается.Тем не менее, является атомарным - он либо успешно (и завершается), либо файловая система не изменяется.Итак, если вы сделаете это:

  1. напишите "file.new" и закройте,
  2. удалите "file",
  3. переименуйте "file.new" в "файл "

, затем при условии успешного выполнения первого шага вы гарантированно сохраните последний" файл "на диске.И просто добавить пару шагов, чтобы у вас всегда была резервная копия «файла».(Если на третьем шаге ничего не получится, у вас останется «file.new» и нет «file». Это может быть восстановлено вручную или автоматически приложением при следующем запуске.)

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

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

0 голосов
/ 08 ноября 2010

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

То, что вы хотите сделать, это атомарно заменить старые файлы резервной копии новыми. К сожалению, я не верю, что Java дает вам достаточный контроль, чтобы делать это напрямую. Вы также должны подумать о том, какие операции являются атомарными в базовой операционной системе. Я знаю файловые системы Linux, поэтому мой ответ будет смещен в сторону Java-программы, работающей в этой системе. Я был бы шокирован, если бы Windows не делала то же самое, но я не могу сказать наверняка.

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

Конечно, перед тем как переименовать, вам необходимо убедиться, что ваш временный файл соответствует. Убедитесь, что все потоковые буферы для файла сброшены в ОС (Channel.force() или OutputStream.flush()), а буферы ОС сброшены на диск (FileOutputStream.getFD.sync()). Конечно, если ваша ОС не отключит кэш записи на самом жестком диске (вероятно, нет), есть вероятность, что ваши данные могут быть повреждены. Добавьте контрольную сумму в XML, если вы действительно хотите быть уверены. Если вы действительно параноик, вы должны очистить кеш операционной системы и буфера жесткого диска и перечитать файл, чтобы убедиться в его совместимости. Это превосходит любые разумные ожидания для обычных потребительских приложений.

Но это просто для атомарной записи и записи одного файла. Ваша проблема более сложна: у вас есть много файлов для атомарного обновления. Например, я скажу, что у вас есть два файла: img.png и main.xml . Я бы сделал один из них:

  1. Простое решение - создать каталог для файла сохранения. Вам не нужно беспокоиться о переименовании каждого отдельного файла, и вы все равно можете атомарно переименовать новый резервный каталог поверх старого, который вы заменяете. То есть, если ваша старая резервная копия - bak / img.png и bak / main.xml , напишите bak.tmp / img.png и bak.tmp / main.xml и переименуйте bak.tmp в bak .
  2. Назовите новые вспомогательные файлы как-нибудь еще и дайте им некоторое время сосуществовать со старыми. То есть напишите img.2.png и main.xml.tmp (что должно означать img.2.png , а не img. png ) и переименовывать только main.xml.tmp в main.xml . Затем удалите img.png .
  3. дополнение: Если у вас нет атомарных переименований, следующая лучшая вещь распространяется на # 2. Каждый раз, когда вы сохраняете проект, присваивайте ему новое имя (например, ver342.xml ). Когда вы загружаете, просто находите самый последний XML , который соответствует (то есть его контрольная сумма проверяется). Держите около 2 или 3, чтобы быть в безопасности. Удаляйте автосохранение только в том случае, если вы успешно восстановили более свежую копию.
...