文件内容损坏的原因
Cause of corrupted file contents
我在野外的一个应用程序中遇到了一个反复出现的问题。
它有一个相当简单的XML文件,它每隔30分钟就会转储一次。
数据文件通常非常小,例如<5KB。
它没有锁定文件,只是每次从头开始重新创建。
我很幸运地看到这个问题发生在一台测试机器上,我观察到的是文件已损坏并设置为"nulls"(即十六进制中的00)。真正奇怪的是,与它应该有的长度相比,它完全是正确的长度。
我试着在保存过程中非常小心:
- 我将xml写入到一个临时文件中,该文件与我要真正保存它的目录相同
- 我使用MoveFile_WRITE_TROUGH集执行Win32 MoveFile()(因此应该块,直到移动真正完成),以移动文件来替换现有的数据文件
我甚至锁定了Mutex,以确保这不是线程问题。
这种情况并不经常发生,大概每1000个用户中就有1个。
现在,我在过去观察到数据文件在写入过程中因电源故障或BSOD而损坏,我也看到过文件的32kb都是NULL。
但考虑到写入过程中电源故障的可能性,尤其是因为我使用的是MOVEFILE_write_TROUGH,这似乎比我预期的要多。
有什么想法吗?
约翰·
一些问题的答案:
-
Q: 为什么不直接写入文件A: 我避免这样做是为了减少软件在电源故障问题上的脆弱性。例如,你写文件到一半时崩溃/powerfail/BSOD,那么你肯定有一个损坏的文件。先写临时文件,然后移动是一种常用且简单的方法,可以确保尽可能地执行原子文件操作(在不使用NTFS特定API的情况下,尽可能接近)。我应该说,该软件是一个存档/备份系统,所以我必须比其他应用程序更注意数据的一致性。
-
Q: 这种情况在正常运行期间发生吗?
-
A: 由于这个问题发生在野外,我只处理了一些线索,所以我不确定。我可以说这个软件99.9%的时间都是可靠的。我想这就是我问题的核心:这只是BSOD/电源故障造成的随机运气不佳,还是一个bug?
-
Q: 什么环境/OS:
-
A: XP、Vista、7、服务器200X。很可能是NTFS,但可能是FAT32
-
Q: 我是否在移动之前关闭文件
-
A: 是的。在进行MoveFile 之前,我使用C++流并调用close()
-
Q: 其他哪些进程正在访问该文件?
- A: 没有由我管理。很明显,我无法控制病毒检查器、文件夹同步器等。该文件位于用户机器的AppData\Local文件夹中
根据我的经验,这可能是由windows中的文件缓存引起的。您应该尝试使用CreateFile()
和FILE_FLAG_WRITE_THROUGH
传入来保存文件。通过这种方式保存文件可以确保文件将进入硬盘。
我编写了一个小程序来测试这个。如果程序用std::ofstream
创建文件,并用MoveFileEx()
和MOVEFILE_WRITE_THROUGH
移动该文件,如果在文件移动完成后立即关闭(而不是关闭)VM,则文件几乎每次都会损坏;否则,如果程序使用CreateFile()
和FILE_FLAG_WRITE_THROUGH
创建文件并再次执行相同的操作,则文件不会损坏(我测试了大约10次,但没有发生)。
经过这些简单的测试后,我认为您应该尝试将CreateFile()
与FILE_FLAG_WRITE_THROUGH
结合使用来解决您的问题。
更多信息:
文件缓存(Windows)
Windows内部,第6版,第11章缓存管理器
以下是一些想法:
- 临界后冲洗流信息或在长时间没有写作
- 验证是否没有其他实体正在写入文件
- 验证缓冲的数据是否被其他代码覆盖
- 在长时间之间关闭文件没有文字
我也遇到了同样的问题,我的代码和你解释的完全一样,这似乎很不正统,但要让它发挥作用,制作多个备份文件对我来说是一个解决方案,而如果出现问题,我会认为它已损坏,并从备份文件中读取。
- 捕获标准输出以压缩并使用 CTRL-C 中断会给出损坏的 zip 文件
- VSCode C++调试文件名中包含中文字符的文件时插件损坏
- Dll中缺少什么(致命错误LNK1107:无效或损坏的文件:)
- 修复可能损坏的 .stl 文件上的法线
- 有没有办法修复因未正确关闭 boost::archive::binary_oarchive 而损坏的文件?
- 窗口中的文件损坏 电源故障后操作系统
- 试图在文件中阅读时堆积损坏
- 编译项目时文件无效或损坏,包括 V8
- 从 /MD Exe 文件中删除 /MDd 的 DLL 内存会导致堆损坏
- 写入文本文件的数据部分损坏且无法恢复
- std::文件系统"root_name"定义在 Windows 上损坏
- 获取无效或损坏的文件LNK1107:尝试链接 OpenSceneGraph 教程.dll时无法0x378读取
- 当我使用文件作为c ++程序的输入时,它会损坏
- 问题是将数据写入特定单元格并且文件已损坏
- 写入文件时出现堆损坏
- OSX "ld" : 如何显示未解析符号的损坏名称?如何获取地图文件?
- 如何检查文件的损坏
- Flashdrive损坏的文件系统上的文本文件恢复
- 可执行文件在被复制时以某种方式损坏
- 在不损坏文件系统的情况下将原始数据"signature"写入磁盘