C++ 文件内容损坏的原因

C++ 文件内容损坏的原因,c++,windows,winapi,file-io,corruption,C++,Windows,Winapi,File Io,Corruption,我经常遇到一个应用程序在野外的问题 它有一个相当简单的XML文件,每隔30分钟就会转储一次 数据文件通常非常小,例如小于5KB 它没有对文件进行锁定,只是每次都从头开始重新创建它 我很幸运地看到问题发生在一台测试机器上,我观察到的是该文件已损坏并设置为“null”(即十六进制中的00)。真正奇怪的是,它的长度与它本应的长度完全相同 我在保存过程中一直非常小心: 我将xml写入一个临时文件,该临时文件位于我要真正保存它的目录中 我使用MoveFile_WRITE_THROUGH集执行Win32 M

我经常遇到一个应用程序在野外的问题

它有一个相当简单的XML文件,每隔30分钟就会转储一次

数据文件通常非常小,例如小于5KB

它没有对文件进行锁定,只是每次都从头开始重新创建它

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

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

  • 我将xml写入一个临时文件,该临时文件位于我要真正保存它的目录中
  • 我使用MoveFile_WRITE_THROUGH集执行Win32 MoveFile()(因此它应该阻止,直到移动真正完成),以移动文件以替换现有数据文件
  • 我甚至锁定了互斥锁以确保这不是线程问题

    这种情况并不经常发生,比如每1000个用户中就有一个

    现在,我在过去观察到数据文件在写入过程中因电源故障或BSOD而损坏,并且我看到文件的32kb都是空的

    但是,考虑到写入过程中可能出现的电源故障,尤其是因为我使用的是MOVEFILE_write_THROUGH,这似乎比我预期的要多

    有什么想法吗

    约翰


    对一些问题的答复:

    • 问:为什么不直接写入文件 答:我避免这样做是为了使软件不易受到断电问题的影响。例如,您正在编写文件并崩溃/powerfail/BSOD,那么您肯定有一个已损坏的文件。执行临时文件写入然后移动是一种常用且简单的方法,可以确保您尽可能地执行原子文件操作(当然,在不使用NTFS特定API的情况下尽可能地接近)。我应该说,该软件是一个归档/备份系统,因此我必须比其他应用程序更加注意数据的一致性

    • 问:在正常运行期间会发生这种情况吗

    • 答:因为这个问题是在野外发生的,所以我只是想了解一些线索,所以我不确定。我可以说,该软件99.9%的时间运行可靠。我想这就是我的问题的核心:这只是由BSOD/电源故障引起的随机不幸,还是一个bug

    • 问:什么环境/操作系统:

    • 答:XP,Vista,7,服务器200X。最有可能是NTFS,但可能是FAT32

    • 问:我是否在移动前关闭文件

    • A:是的。在使用MOVELISH文件

    • 之前,我使用C++流和调用CULL()
    • 问:还有哪些进程正在访问该文件

    • A:没有一个是我管理的。显然,我无法控制病毒检查器、文件夹同步器等。该文件位于用户计算机的AppData\Local文件夹中
      • 以下是一些想法:

        • 在紧急情况下冲洗水流 信息或在长时间的 没有文字
        • 确认没有其他实体被删除 正在写入文件
        • 验证缓冲的数据是否不正确 被其他代码覆盖
        • 在长持续时间之间关闭文件 没有文字

        根据我的经验,这可能是由windows中的文件缓存引起的。您应该尝试使用
        CreateFile()
        file\u FLAG\u WRITE\u通过传递来保存文件。通过这种方式保存文件可以确保文件将进入硬盘

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

        在这些简单的测试之后,我认为您应该尝试使用
        CreateFile()
        FILE\u-FLAG\u-WRITE\u-to
        来解决您的问题

        更多信息:


        Windows内部构件,第6版,第11章缓存管理器

        为什么要这么麻烦?真的值得吗?为什么不直接写入文件并避免所有互斥、移动内容等。这种情况是否仅在写入期间或之后不久发生电源故障或崩溃时才会发生?或者在正常操作过程中也会发生这种情况?另外,您的目标是哪个版本的windows?是否在移动临时文件之前关闭临时文件?您的用户是否可能使用FAT?还有哪些其他进程正在访问该文件,以及如何访问?我不会让该文件保持打开状态。我每次都从头开始写这个文件。