Причина поврежденного содержимого файла - PullRequest
7 голосов
/ 29 июня 2011

У меня постоянно возникают проблемы с приложением в дикой природе.

Он имеет довольно простой XML-файл, который время от времени выдает, примерно каждые 30 минут.

Файлы данных часто бывают довольно маленькими - например, <5 КБ. </p>

Он не блокирует файл - он просто каждый раз воссоздает его с нуля.

Мне посчастливилось увидеть, что проблема возникла на тестовой машине, и я заметил, что файл поврежден и имеет значение «ноль» (т. Е. 00 в шестнадцатеричном формате). Что действительно странно, так это то, что это точно правильная длина по сравнению с той, которая должна была быть.

Я пытался быть очень осторожным в процессе сохранения:

  1. Я записываю xml во временный файл в том же каталоге, в котором собираюсь его реально сохранить
  2. Я выполняю Win32 MoveFile () с набором MOVEFILE_WRITE_THROUGH (поэтому должен блокировать до тех пор, пока перемещение не будет действительно и действительно завершено), чтобы переместить файл для замены существующего файла данных

Я даже заблокировал Mutex, чтобы убедиться, что это не проблема с потоками.

Это случается не так часто, как, например, 1 на 1000 пользователей.

В прошлом я наблюдал, как файлы данных были повреждены из-за сбоя питания или BSOD во время записи, и я видел такие вещи, как 32 КБ файла, которые все имеют значение NULL.

Но похоже, что это происходит больше, чем я ожидал, учитывая вероятность сбоя питания во время записи, и особенно, поскольку я использую MOVEFILE_WRITE_THROUGH.

Есть идеи?

John


Ответы на некоторые вопросы:

  • В: Почему бы не записать файл напрямую A: Я избежал этого, чтобы сделать программное обеспечение менее уязвимым для проблем сбоя питания. Например. вы наполовину записываете файл и вы видите аварийный файл / powerfail / BSOD, тогда у вас точно есть поврежденный файл. Выполнение записи во временный файл, а затем перемещение - это наиболее часто используемый и простой способ убедиться, что вы выполняете элементарную файловую операцию, насколько это возможно (ну, насколько это возможно, без использования специфичных для NTFS API). Я должен сказать, что программное обеспечение представляет собой систему архивирования / резервного копирования, поэтому я должен больше заботиться о согласованности данных, чем другие приложения.

  • В: Это происходит при нормальной работе?

  • A: Поскольку эта проблема возникает в дикой природе, я работаю только с несколькими подсказками, поэтому я точно не знаю. Я могу сказать, что программное обеспечение работает надежно в 99,9% случаев. Я думаю, это суть моего вопроса: это просто случайная неудача, вызванная отказом BSOD / power, или это ошибка?

  • В: Какая среда / ОС:

  • A: XP, Vista, 7, Server 200X. Скорее всего NTFS, но может быть FAT32

  • В: Я закрываю файл перед перемещением

  • A: Да. Я использую потоки C ++ и вызываю close () перед тем, как сделать MoveFile

  • В: Какие другие процессы обращаются к файлу?

  • A: Никто не управляет мной. Очевидно, я не контролирую Virus Checker, Folder Syncers и т. Д. Файл находится в папке AppData \ Local на компьютере пользователя.

Ответы [ 2 ]

4 голосов
/ 19 июня 2014

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

Я написал небольшую программу для проверки этого.Если программа создает файл с помощью std::ofstream и использует MoveFileEx() с MOVEFILE_WRITE_THROUGH для перемещения этого файла, файл будет поврежден почти каждый раз, если отключение (не выключение) виртуальной машины сразу после завершения перемещения файла;В противном случае, если программа использует CreateFile() с FILE_FLAG_WRITE_THROUGH для создания файла и делает то же самое снова, файл не поврежден (я тестировал около 10 раз, но этого не произошло).

После этих простых тестов, я думаю, вы должны попытаться использовать CreateFile() с FILE_FLAG_WRITE_THROUGH для решения вашей проблемы.

Дополнительная информация:
Кэширование файлов (Windows)
Windows Internals, 6-е издание, глава 11 Cache Manager

0 голосов
/ 29 июня 2011

Вот несколько идей:

  • Очистка потока после критической информации или перед длительными периодами отсутствия записи.
  • Убедитесь, что никакие другие объекты не записывают в файл.
  • Убедитесь, что буферизованные данные не перезаписаны другим кодом.
  • Закройте файл в течение длительного времени без записи.
...