【问题标题】:Cause of corrupted file contents文件内容损坏的原因
【发布时间】:2011-09-25 10:31:57
【问题描述】:

我在使用某个应用时经常遇到问题。

它有一个相当简单的 XML 文件,它时不时地转储出来,大约每 30 分钟一次。

数据文件通常很小 - 例如

它不会锁定文件 - 它只是每次从头开始重新创建它。

我很幸运地看到问题发生在测试机器上,我观察到文件已损坏并设置为“nulls”(即十六进制中的 00)。真正奇怪的是,与应有的长度相比,它的长度完全正确。

我在保存过程中非常小心:

  1. 我将 xml 写入同一目录中的临时文件,因为我要真正保存它
  2. 我在设置 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


【解决方案1】:

根据我的经验,这可能是由 Windows 中的文件缓存引起的。您应该尝试使用CreateFile() 保存文件并传入FILE_FLAG_WRITE_THROUGH。通过这种方式保存文件可以确保文件将落在硬盘中。

我写了一个小程序来测试这个。如果程序使用std::ofstream 创建文件并使用MoveFileEx() 和MOVEFILE_WRITE_THROUGH 移动该文件,则文件几乎每次在文件移动完成后立即关闭(而不是关闭)VM 时都会损坏;否则,如果程序使用CreateFile() 和FILE_FLAG_WRITE_THROUGH 创建文件并再次执行相同操作,则文件没有损坏(我测试了大约10 次,但没有发生)。

经过这些简单的测试,我认为您应该尝试使用CreateFile() 和FILE_FLAG_WRITE_THROUGH 来解决您的问题。

更多信息:
File Caching (Windows)
Windows Internals,第 6 版,第 11 章缓存管理器

【讨论】:

    【解决方案2】:

    这里有一些想法:

    • 在关键后刷新流 信息或之前的很长一段时间 不写。
    • 确认没有其他实体 写入文件。
    • 验证缓冲的数据不是 被其他代码覆盖。
    • 在长时间之间关闭文件 没有文字。

    【讨论】:

    • 我没有保持文件打开。我每次都从头开始编写文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2010-12-03
    相关资源
    最近更新 更多