在Windows上以事务方式编写文件更改 [英] Transactionally write a file change on Windows

查看:164
本文介绍了在Windows上以事务方式编写文件更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

官方微软推荐关于如何确保代表特定状态的文件以一致的方式编写,将其写入临时文件并 ReplaceFile 它。

An official microsoft recommendation on how to ensure that a file, representing a particular state, is written in a consistent way is to write it into a temporary file and ReplaceFile it.

但是如果我们假设一个更高级别的任务 - 改变文件中表示的状态 - 它就会变得有点麻烦。

But if we'll assume a bit more higher-level task - a change to the state represented in the file - it becomes a bit more problematic.

制作一个更改为文件中的状态,您需要从文件中读取状态,进行更改并将其写回。虽然写作部分可能会被 ReplaceFile 函数,因为我们读过它后该文件可能已被更改的事实不是。

To make a change to a state within a file, you need to read the state from the file, make the change and write it back. While the "writing" portion we may consider be covered by the ReplaceFile function, the fact that the file could have been changed since we've read it is not.

换句话说,我们可能需要检查文件是否仍然相同并且在 ReplaceFile 电话。如果我们在这里谈论文本编辑器 - 在调用之前进行修改时间检查就足够了。但是如果我们想要一些更强大的东西 - 我们应该在修改时间检查之后但在通话之前确认
文件更改的可能性。

In other words, we may need to check if the file is still the same and has not updated since, before the ReplaceFile call. If we are about talking text editors here - a modification time check before the call should be enough. But if we want something a bit more robust - we should acknowledge the possibility of file changing after the modification time check, but before the call.

天真方法是实现 CompareAndReplaceFile 调用,它将锁定原始文件,检查它是否是同一个文件,然后复制 ReplaceFile 。这不仅是一个有点hacky解决方案(系统函数的复制粘贴逻辑不是一个好的做法),但它也意味着更长的锁定时间。

The naive approach would be to implement a CompareAndReplaceFile call, that will lock the original file, check that it's the same file, then replicating what ReplaceFile does. Nor only this is a bit hacky solution (copy-pasting logic of a system function is not a good practice), but it also implies a longer lock period.

例如在Linux上,使用 fcntl(2)<可以实现同样的效果/ a>的( FD_SETLEASE )文件租用有可能在其他人打开文件进行写入时中止操作,在 rename(2),这是原子的,不会打开文件,所以你可以通过它保持租约。

For instance, on Linux, the same effect could be achieved by utilizing fcntl(2)'s (FD_SETLEASE) file leasing to have a chance of aborting your operation once someone else opens a file for writing, prior to rename(2), which is atomic and does not open a file, so you can keep a lease through it.

除了上面讨论的hacky解决方案之外,还有办法在Windows上实现事务性文件更改吗?

Are there ways to implement a transactional file change on Windows, aside of a hacky solution discussed above?

推荐答案

使用 CreateFile 打开文件时,设置共享模式。如果你没有指定 FILE_SHARE_WRITE ,那么在你关闭句柄之前没有人可以打开文件进行写访问(如果文件已经打开以进行写访问,你的尝试失败,共享违规)。

When you open a file using CreateFile, you set the sharing mode. If you don't specify FILE_SHARE_WRITE, no one can open the file for write access until you close it the handle (and if the file is already open for write access, your attempt fails with a sharing violation).

因为 ReplaceFile 使用 GENERIC_READ执行操作,DELETE ,和SYNCHRONIZE 标志和 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE 共享模式,您可以使用 FILE_SHARE_READ |的共享模式打开您的写入句柄。 FILE_SHARE_DELETE 并在调用 ReplaceFile 之后保持打开状态,从而排除竞争条件。

Because ReplaceFile performs its operation with GENERIC_READ, DELETE, and SYNCHRONIZE flags and a FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE sharing mode, you can open your write handle using a sharing mode of FILE_SHARE_READ | FILE_SHARE_DELETE and keep it open until after the call to ReplaceFile, thus excluding the race condition.

如果您将内容保留在内存中(文本编辑器案例),那么在保存时您将:

If you're holding the content in memory (the text editor case), then when saving you would:


  • 重新打开文件使用 GENERIC_WRITE 和共享模式 FILE_SHARE_READ | FILE_SHARE_DELETE (如果原始句柄包含 FILE_SHARE_WRITE ,不包括 GENERIC_WRITE ,或者读入工作缓冲区后关闭)

  • 执行修改时间检查。

  • 将更改写入新的临时文件。

  • 致电 ReplaceFile

  • 关闭替换文件的句柄。

  • Reopen the file using GENERIC_WRITE and sharing mode FILE_SHARE_READ | FILE_SHARE_DELETE (if the original handle included FILE_SHARE_WRITE, didn't include GENERIC_WRITE, or has been closed after reading into the working buffer)
  • Perform the modification time check.
  • Write the changes to a new temporary file.
  • Call ReplaceFile
  • Close the handle to the replaced file.

如果第一步因共享冲突而失败,或第二步显示另一项更改,则需要阅读更改的内容,进行三向合并,然后启动过程结束。

If step one fails with a sharing violation, or step two reveals another change, you'll need to read the changed content, do a three-way merge, and start the process over.

这篇关于在Windows上以事务方式编写文件更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆