我们的产品在每个打开的文档文件上均具有写排斥文件句柄,以确保我们对该文件具有专有写控制。
因此,Windows不允许任何其他进程执行比从文件读取更多的操作,也不能从资源管理器或其他进程删除该文件-因为该文件具有打开(且不包括写操作)的句柄。
但是,在一些非常奇怪的情况下(文件内容已损坏),我们一直遇到麻烦。我认为这与bug或可能是我对Windows API保证的误解有关-即为了将设计文件保存在先前版本的顶部-我们目前持有文件句柄-我必须倒带句柄开始文件,将其写出,然后强制其在该新位置冲洗并截断(以防文件缩小-我们不希望文件末尾出现多余污泥-那也将是一种损坏形式) )。在 session 中多次执行此操作-每次用户编辑然后保存更改...
但是,有时我们的客户报告所有这些导致的损坏文件(仅通过网络-从未在本地)。
我们认为这可能是由于我们的实际保存过程稍微复杂一些:
可能只是“不刷新,查找,写入,刷新”的情况-这会在MS的网络文件系统代码中引入细微的错误(或依赖于系统内置的不确定性,因此无法可靠地依赖)吗?
因此,我正在实现两层修复程序:
No. 2具有一些不错的功能-例如“如果在写新文件时遇到问题,则旧文件保持不变”。这意味着最坏的情况是不会保存新数据,但不会丢失旧数据。
这是经典模式“建立新拷贝,然后将其交换为真实/ Activity 数据结构”的基本用法。
很好-但是我不知道该如何“交换文件内容”?
我可以做经典的:
(当然,我首先需要删除任何以前的A.bak)。
很好-但同样-我们通常在A上有一个锁定的句柄。因此这扩展到了一些不完美的地方:
我对此不满意的是“ Activity 部件过多”。
您不认为会发生这种情况-但是,文件系统索引编制,防病毒或备份软件都可以而且非常非常经常地(按照我们的经验)进行操作。
所以-理想情况下,我绝对不想在任何时候放弃对A的控制!我想确保每次交接都不会受到防病毒软件或其他软件的干扰,因为它们进入并完善了它们。
实际上,理想情况下,我会:
那么,是否有其他人发现了交换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/