是否有标准的文件保存和交换模式
Is there a standard file save and swap pattern?
我们的产品在每个打开的文档文件上都有一个独占写入文件句柄,以确保我们对文件具有独占的写入控制。
因此,Windows 不允许任何其他进程执行比从文件读取更多的操作,也不能从资源管理器或其他进程中删除该文件 - 因为它上的打开(和写入独占)句柄。
但是,我们遇到了非常奇怪的边缘情况,即文件的内容已损坏。 我认为这与错误有关,或者可能是我对 Windows API 保证的内容的误解 - 即为了将设计文件保存在以前版本的顶部 - 我们目前持有文件句柄 - 我必须倒带句柄到文件的开头,写出来,然后强制它刷新并在新位置截断(以防文件缩小 - 我们不想要额外的我们文件末尾的污泥 - 这也是一种腐败形式)。 在会话期间多次执行此操作 - 每次用户编辑时都会保存其更改...
但是,有时我们的客户会报告所有这些导致损坏的文件(仅通过网络 - 从不在本地)。
我们认为这可能是因为我们的实际保存过程稍微复杂一些:
- 倒带(已打开的)文件句柄
- 写出核心数据
- 齐平并截断手柄
- 搜索到文件末尾
- 写出缩略图图像数据(本质上 - 附加缩略图)
- 齐平并截断手柄
这可能只是一个"不要刷新,搜索,写入,刷新"的情况 - 这在MS的网络文件系统代码中引入了微妙的错误(或依赖于系统内置的不确定性 - 并且不能可靠地依赖)?
因此,我正在实施两层修复:
- 执行单次倒带,然后写入核心数据 + 图像数据 + 刷新和截断(一次)
- 执行临时另存、关闭、重命名
No. 2 有一些不错的功能 - 例如"如果写出新文件时出现问题,旧文件保持不变。 这意味着在最坏的情况下,他们的新数据不会被保存,但没有旧数据丢失。
这是"构建一个新副本,然后将其交换为真实/活动数据结构"经典模式的基本用法。
很棒 - 但我不知道如何"交换文件内容"?
我可以做经典的:
- 完全写入 T(温度)并关闭它。
- 将 A(实际)文件重命名为 A.bak。
- 将 T 重命名为 A
(当然,我需要先删除任何以前的 A.bak)。
这很好 - 但同样 - 我们通常在 A 上有一个锁定的手柄。 所以这扩展到有点不完美:
- 写 T
- 关闭我们在 A 上的手柄
- 将 A 重命名为 A.bak
- 将 T 重命名为 A
- 获取 A 上的独占写入句柄
我不喜欢的是"活动部件太多"。
- 在 2 到 5 之间,其他人都可以抓住 A 上的锁或以其他方式妨碍我们。
您不认为它会发生 - 但是文件系统索引或防病毒或备份软件都可能妨碍您,并且非常 - 非常 - 经常(根据我们的经验)。
所以 - 理想情况下,我不想在任何时候放弃对 A 的控制! 我想确保每次交接都不会受到防病毒软件或其他软件的影响,以免进入那里并解决问题。
理想情况下,事实上,我会:
- 写 T
- 交换 T 和 A 的内脏(要求文件系统实际将名称 A 链接到 T 的内容)
- 永远幸福地生活...
那么,有没有其他人发现的交换T和A的模式呢?
是否有一组 API 调用来使其更好/更健壮?
其他想法可能有助于重新思考我的方法?
注意:MS 已弃用事务文件系统 API。 所以这听起来像是一个非启动器 - 更不用说它无论如何都不适用于 Windows 下的所有文件系统。
更新: FWIW,我将其实现为写入临时文件,重命名原始文件,将临时重命名为真实文件,删除原始文件(加上必要的解锁并获得新锁)使用 RAII 和 ScopeGuard 来处理任何故障回滚,当然回滚 - 副作用和操作系统相关,是"最佳情况",不如C++语言合同本身得到很好的保证。 尽管如此,在测试期间它还是非常有效的 - 从来没有给我一个坏文件(我有意无意地创造了许多问题,这些问题创建了一个糟糕的临时文件,或者在调用展开过程的算法期间出现错误(抛出异常)。
更新 2:">
最终"算法为
1。(保存到临时本地验证副本)
2. 保存到临时新文件
3.(验证新的保存和验证匹配)4. 将我们的锁放在真实文件
上 5. 将
真实文件重命名为临时旧文件,并将原始文件替换为临时文件(这包括传输属性、ACL 和时间戳 - 请参阅 ReplaceFile())
6. 获取我们的锁(如果它被锁定)
7.成功(抛弃我们的守卫)
ReplaceFile 是一种相当标准的方法。
它不能解决您的保持锁定问题,但它是您实现的测试版本,具有其他功能,例如将任何 ACL 从旧文件传输到新文件。
如果您保留自制实现,请确保处理Windows上的文件删除并不总是立即的情况。 例如,如果在将当前文件重命名为备份文件之前必须删除旧的"备份"文件,则重命名可能会失败。
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 为什么在保护模式下继承升级不起作用
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- C++嵌套if语句,基本货币交换
- 此模式的C++RegEx
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- shell排序中的交换和比较
- 使用可变模板的Broadcaster/Listener模式
- c++方法参数只能在linux的发布模式下自行更改
- 资源管理设计模式
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- 通过交换元素使数组相同
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 为什么在使用VK_PRESENT_MODE_FIFO_KHR呈现模式调整交换链图像大小时出现白色闪烁
- 是否有标准的文件保存和交换模式
- MPI 中的鬼细胞交换模式
- 数据交换的设计模式