J’ai un problème récurrent avec une application dans la nature.
Il contient un fichier XML assez simple qu’il vide de temps en temps, quelque chose comme toutes les 30 minutes.
Les fichiers de données sont souvent assez petits, par exemple <5 Ko.
Il ne maintient pas un verrou sur le fichier – il ne fait que le recréer à partir de zéro à chaque fois.
J’ai eu la chance de voir le problème se produire sur une machine de test et ce que j’ai observé, c’est que le fichier était corrompu et mis à “nulls” (c’est-à-dire 00 dans Hex). Ce qui est vraiment étrange, c’est que c’est exactement la bonne longueur par rapport à ce qu’elle aurait dû être.
J’ai essayé d’être très prudent dans mon processus de sauvegarde:
Je verrouille même un Mutex pour m’assurer qu’il ne s’agit pas d’un problème de threading.
Cela n’arrive pas souvent, comme peut-être 1 utilisateur sur 1000.
Maintenant, dans le passé, j’ai observé des fichiers de données corrompus par une panne de courant ou un BSOD lors de l’écriture, et j’ai vu des choses comme le 32kb d’un fichier étant tout NULL.
Mais il semble juste que cela se produise plus que ce à quoi je m’attendais, étant donné les risques de coupure de courant pendant l’écriture, et en particulier depuis que j’utilise MOVEFILE_WRITE_THROUGH.
Des idées?
John
Réponses à quelques questions:
Q: Pourquoi ne pas écrire directement dans le fichier? A: Je l’ai évité pour rendre le logiciel moins vulnérable aux problèmes de panne de courant. Par exemple, vous êtes à mi-chemin dans l’écriture du fichier et de crash / powerfail / BSOD, alors vous avez certainement un fichier corrompu. Faire un fichier temporaire en écriture puis en déplacement est un moyen simple et couramment utilisé pour vous assurer que vous effectuez une opération de fichier atomique le plus possible (enfin, aussi proche que possible sans utiliser des API spécifiques à NTFS). Je devrais dire que le logiciel est un système d’archivage / sauvegarde, alors je dois faire plus attention à la cohérence des données que d’autres applications.
Q: Cela se produit-il pendant le fonctionnement normal?
R: Comme ce problème se pose à l’état sauvage, je ne travaille qu’avec quelques indices, alors je ne sais pas avec certitude. Je peux dire que le logiciel fonctionne à 99,9% du temps. J’imagine que c’est le nœud de ma question: est-ce juste un manque de chance aléatoire causé par une panne de BSOD ou une panne de courant?
Q: Quel environnement / OS:
A: XP, Vista, 7, Server 200X. Très probablement NTFS, mais pourrait être FAT32
Q: Est-ce que je ferme le fichier avant de déplacer
Un: oui. J’utilise les stream C ++ et appelle close () avant de faire le MoveFile
Q: Quels autres processus accèdent au fichier?
Comme mon expérience, il est possible que ce soit par cache de fichiers dans Windows. Vous devriez essayer de sauvegarder le fichier en utilisant CreateFile()
avec FILE_FLAG_WRITE_THROUGH
pass in. Enregistrer le fichier de cette façon peut vous assurer que le fichier va atterrir sur le disque dur.
J’avais écrit un petit programme pour le tester. Si le programme crée un fichier avec std::ofstream
et utilise MoveFileEx()
avec MOVEFILE_WRITE_THROUGH
pour déplacer ce fichier, le fichier est corrompu presque chaque fois s’il est hors tension (et non pas arrêté) immédiatement après la fin du fichier; Sinon, si le programme utilise CreateFile()
avec FILE_FLAG_WRITE_THROUGH
pour créer un fichier et refait la même chose, le fichier n’a pas été corrompu (j’ai testé environ 10 fois, mais cela ne s’est pas produit).
Après ces tests simples, je pense que vous devriez essayer d’utiliser CreateFile()
avec FILE_FLAG_WRITE_THROUGH
pour résoudre votre problème.
Plus d’information:
Mise en cache de fichiers (Windows)
Windows Internals, 6ème édition, Chapitre 11 Cache Manager
Voici quelques idées: