【发布时间】:2011-09-25 10:31:57
【问题描述】:
我在使用某个应用时经常遇到问题。
它有一个相当简单的 XML 文件,它时不时地转储出来,大约每 30 分钟一次。
数据文件通常很小 - 例如
它不会锁定文件 - 它只是每次从头开始重新创建它。
我很幸运地看到问题发生在测试机器上,我观察到文件已损坏并设置为“nulls”(即十六进制中的 00)。真正奇怪的是,与应有的长度相比,它的长度完全正确。
我在保存过程中非常小心:
- 我将 xml 写入同一目录中的临时文件,因为我要真正保存它
- 我在设置 MOVEFILE_WRITE_THROUGH 的情况下执行 Win32 MoveFile()(因此它应该阻塞直到移动真正完成),移动文件以替换现有数据文件
我什至锁定了一个 Mutex 以确保这不是线程问题。
这种情况并不经常发生,比如千分之一的用户。
现在我过去观察到数据文件在写入过程中因电源故障或 BSOD 而损坏,并且我看到文件的 32kb 全部为 NULL。
但考虑到写入过程中出现电源故障的可能性,尤其是因为我使用的是 MOVEFILE_WRITE_THROUGH,它似乎比我预期的要多。
有什么想法吗?
约翰
一些问题的答案:
问:为什么不直接写入文件 答:我避免这样做是为了使软件不易受到电源故障问题的影响。例如。你正在编写文件和崩溃/powerfail/BSOD,那么你肯定有一个损坏的文件。执行临时文件写入然后移动是一种常用且简单的方法,可确保您尽可能执行原子文件操作(好吧,在不使用 NTFS 特定 API 的情况下尽可能接近)。我应该说这个软件是一个存档/备份系统,所以我必须比其他应用程序更注意数据的一致性。
问:在正常运行期间会发生这种情况吗?
答:由于这个问题在野外发生,我只是在处理一些线索,所以我不确定。我可以说该软件在 99.9% 的时间里都能可靠地工作。我想这就是我的问题的关键:这只是由 BSOD/电源故障引起的随机不幸还是一个错误?
问:什么环境/操作系统:
答:XP、Vista、7、Server 200X。最有可能是 NTFS,但也可能是 FAT32
问:我要在移动前关闭文件吗
答:是的。在执行 MoveFile 之前,我正在使用 C++ 流并调用 close()
问:还有哪些进程正在访问该文件?
- A:没有一个由我管理。显然我无法控制病毒检查器、文件夹同步器等。该文件位于用户计算机的 AppData\Local 文件夹中。
【问题讨论】:
-
为什么要这么麻烦?是不是真的值得吗?为什么不直接写入文件并避免所有互斥锁、移动内容等。
-
是否只有在写入过程中或写入后不久发生电源故障或崩溃时才会发生这种情况?还是在正常操作期间也会发生?
-
另外,您的目标是哪些版本的 Windows?
-
您是否在移动临时文件之前将其关闭?您的用户是否可能使用 FAT?
-
还有哪些进程正在访问该文件,以及如何访问?
标签: c++ windows winapi file-io corruption