c++ - 有标准的文件保存和交换模式吗?

标签 c++ windows file file-handling

我们的产品在每个打开的文档文件上均具有写排斥文件句柄,以确保我们对该文件具有专有写控制。

因此,Windows不允许任何其他进程执行比从文件读取更多的操作,也不能从资源管理器或其他进程删除该文件-因为该文件具有打开(且不包括写操作)的句柄。

但是,在一些非常奇怪的情况下(文件内容已损坏),我们一直遇到麻烦。我认为这与bug或可能是我对Windows API保证的误解有关-即为了将设计文件保存在先前版本的顶部-我们目前持有文件句柄-我必须倒带句柄开始文件,将其写出,然后强制其在该新位置冲洗并截断(以防文件缩小-我们不希望文件末尾出现多余污泥-那也将是一种损坏形式) )。在 session 中多次执行此操作-每次用户编辑然后保存更改...

但是,有时我们的客户报告所有这些导致的损坏文件(仅通过网络-从未在本地)。

我们认为这可能是由于我们的实际保存过程稍微复杂一些:

  • 倒带(已打开)文件句柄
  • 写出核心数据
  • 刷新并截断句柄
  • fseek到文件
  • 的末尾
  • 写出缩略图图像数据(基本上-附加缩略图)
  • 刷新并截断句柄

  • 可能只是“不刷新,查找,写入,刷新”的情况-这会在MS的网络文件系统代码中引入细微的错误(或依赖于系统内置的不确定性,因此无法可靠地依赖)吗?

    因此,我正在实现两层修复程序:
  • 进行一次倒带,然后写入核心数据+图像数据+刷新并截断(一次)
  • 做一个另存为,关闭,重命名

  • No. 2具有一些不错的功能-例如“如果在写新文件时遇到问题,则旧文件保持不变”。这意味着最坏的情况是不会保存新数据,但不会丢失旧数据。

    这是经典模式“建立新拷贝,然后将其交换为真实/ Activity 数据结构”的基本用法。

    很好-但是我不知道该如何“交换文件内容”?

    我可以做经典的:
  • 完全写入T(临时)并将其关闭。
  • 将一个(实际)文件重命名为A.bak。
  • 将T重命名为A

  • (当然,我首先需要删除任何以前的A.bak)。

    很好-但同样-我们通常在A上有一个锁定的句柄。因此这扩展到了一些不完美的地方:
  • 写T
  • 关闭
  • 的句柄
  • 将A重命名为A.bak
  • 将T重命名为A
  • 获取A
  • 上的写排斥句柄

    我对此不满意的是“ Activity 部件过多”。
  • 在2到5之间,其他任何人都可以锁定A或以其他方式妨碍我们。

  • 您不认为会发生这种情况-但是,文件系统索引编制,防病毒或备份软件都可以而且非常非常经常地(按照我们的经验)进行操作。

    所以-理想情况下,我绝对不想在任何时候放弃对A的控制!我想确保每次交接都不会受到防病毒软件或其他软件的干扰,因为它们进入并完善了它们。

    实际上,理想情况下,我会:
  • 写T
  • 交换T和A(要求文件系统实际将名称A链接到T的内容)
  • 永远幸福快乐地生活...

  • 那么,是否有其他人发现了交换T和A的模式?

    是否有一组API调用可以使此功能更好/更强大?

    完全可以帮助我重新思考我的方法的其他想法?

    注意:MS已弃用事务性文件系统API。因此,这听起来像是一个入门者-更不用说它并非在Windows下的所有文件系统上都可用。

    更新: FWIW,我将其实现为写入临时文件,将原始文件重命名,将临时文件重命名为真实文件,使用RAII和ScopeGuard来删除原始文件(加上必要的解锁并获得新的锁定)来处理所有失败回滚,尽管如此回滚-副作用和与操作系统有关,是“最佳情况”,不能像C++语言本身签订契约(Contract)那样得到保证。尽管如此,在测试过程中它还是非常有效的-从未给我一个坏文件(并且我有意无意地创建了许多问题,这些问题导致了临时文件的损坏或在调用展开过程的算法中出错(引发了异常))。

    更新2:“最终”算法用于
    1.(保存到临时本地验证拷贝)
    2.保存到一个临时的新文件
    3.(验证新的保存和验证匹配)
    4.放下对真实文件的锁定
    5.将实际文件重命名为临时旧文件,然后用临时文件替换原始文件(这包括传输属性,ACL和时间戳-请参见ReplaceFile())
    6.获取我们的锁(如果已锁定)
    7.成功(放弃我们的 guard )

    最佳答案

    ReplaceFile是一种相当标准的方法。

    它不能解决您的锁定问题,但它是您实现的测试版,具有其他功能,如将任何ACL从旧文件传输到新文件。

    如果保留自制程序实现,请确保处理Windows上的文件删除并非总是立即发生的情况。例如,如果在将当前文件重命名为备份文件之前必须删除旧的“备份”文件,则重命名可能会失败。

    关于c++ - 有标准的文件保存和交换模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50804308/

    相关文章:

    java - 如何在java中找到非常大的文件复制状态

    javascript - 如何将从客户端浏览器抓取的数据保存到用户文件中?使用 Electron ?

    c++ - for循环递减不起作用

    c++ - mingw-w64 和 SDL2 链接问题

    c++ - opengL画一条线

    windows - 终端中是/否问题的标准格式?

    c++ - 是否可以编写 C++ 基类成员函数来实例化从中调用它的任何派生类?

    windows - 我想实现一个文件资源管理器,如何读取文件的图标并显示它们?

    windows - 如何使用 Packer 在 Azure 中构建具有大文件的镜像?

    python - 将文件解析为python中的字典