我在使用应用程序时遇到反复出现的问题。
它有一个相当简单的 XML 文件,它时不时地转储出来,大约每 30 分钟一次。
数据文件通常很小——例如< 5KB。
它不会锁定文件 - 它只是每次都从头开始重新创建它。
我很幸运在测试机器上看到了问题,我观察到文件已损坏并设置为“空值”(即十六进制的 00)。真正奇怪的是,与应该的长度相比,它的长度恰好是正确的。
我在保存过程中非常小心:
- 我将 xml 写入一个临时文件,该文件位于我要真正保存它的同一目录中
- 我执行 Win32 MoveFile() 并设置了 MOVEFILE_WRITE_THROUGH(因此它应该阻塞直到移动真正完成),以移动文件以替换现有数据文件
我什至锁定了一个 Mutex 以确保这不是线程问题。
这种情况并不经常发生,大约每 1000 个用户中就有 1 个。
现在我过去曾观察到数据文件在写入过程中因电源故障或 BSOD 而损坏,并且我看到过诸如文件的 32kb 全部为 NULL 之类的情况。
但它似乎发生的比我预期的要多,考虑到写入过程中可能会出现电源故障,尤其是因为我正在使用 MOVEFILE_WRITE_THROUGH。
有什么想法吗?
约翰
一些问题的答案:
问:为什么不直接写入文件 答:我避免了这一点,以使软件不易受到电源故障问题的影响。例如。你在写入文件的一半时崩溃/电源故障/BSOD 那么你肯定有一个损坏的文件。执行临时文件写入然后移动是一种常用且简单的方法,可确保您尽可能执行原子文件操作(嗯,在不使用 NTFS 特定 API 的情况下尽可能接近)。我应该说该软件是一个归档/备份系统,因此我必须比其他应用程序更加注意数据的一致性。
问:正常运行时会出现这种情况吗?
答:由于这个问题是在野外发生的,我只是在处理一些线索,所以我不确定。我可以说该软件在 99.9% 的时间里都能可靠地工作。我想这就是我的问题的核心:这只是由 BSOD/电源故障引起的随机不幸还是一个错误?
问:什么环境/操作系统:
答:XP、Vista、7、Server 200X。最有可能是 NTFS,但也可能是 FAT32
问:我是不是在移动前关闭文件
答:是的。我正在使用 C++ 流并在执行 MoveFile 之前调用 close()
问:还有哪些其他进程正在访问该文件?
- A:没有一个是我管理的。显然,我无法控制病毒检查器、文件夹同步器等。该文件位于用户计算机的 AppData\Local 文件夹中。
最佳答案
根据我的经验,这可能是由Windows 中的文件缓存引起的。您应该尝试使用 CreateFile()
并传入 FILE_FLAG_WRITE_THROUGH
来保存文件。通过这种方式保存文件可以确保文件将登陆硬盘。
我写了一个小程序来测试这个。如果程序使用 std::ofstream
创建文件并使用 MoveFileEx()
和 MOVEFILE_WRITE_THROUGH
移动该文件,文件几乎每次都会损坏,如果文件移动完成后立即关闭(不是关闭)虚拟机;否则,如果程序使用 CreateFile()
和 FILE_FLAG_WRITE_THROUGH
创建文件并再次做同样的事情,文件没有损坏(我测试了大约 10 次,但它没有发生)。
经过这些简单的测试,我认为您应该尝试使用 CreateFile()
和 FILE_FLAG_WRITE_THROUGH
来解决您的问题。
更多信息:
File Caching (Windows)
Windows Internals,第 6 版,第 11 章缓存管理器
关于c++ - 文件内容损坏的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6525943/