重写现有文件,以便仅在完全写入后才自动将其替换为新版本

重写现有文件,以便仅在完全写入后才自动将其替换为新版本

我依稀记得在某处读过,在某些 Unices 中,曾经有一种打开现有文件进行写入的方法,带有一个要求内核使用旧版本的标志(供其他进程访问它进行读取),直到“新版本” " 版本已完全写入(fd 已关闭),从此时起该文件显示为新版本。

换句话说,其他进程要么看到旧版本,要么看到新版本,而绝不会看到不完整编写的版本。

有了解的人可以给我指点参考吗?

答案1

您所描述的内容听起来与覆盖文件的基本重命名完全相同。

当您重命名/移动一个文件到另一个文件之上时,旧文件将被取消链接。这意味着该文件仍然存在,但它不再位于文件系统树中。因此,只要旧应用程序保持文件打开状态,就可以继续访问该文件。一旦所有应用程序都关闭了旧文件,那么它实际上在磁盘上未分配。

系统rename调用是一个原子操作。因此,要执行此操作,您需要使用不同的名称创建一个新文件,然后调用rename将临时文件重命名为您想要替换的文件。由于操作是原子的,因此绝对不存在文件丢失的情况。它立即从旧文件转到新文件。
但请注意,临时文件和被替换的文件必须驻留在同一安装点上。

答案2

作为帕特里克写道,通常的方法是将新版本写入单独的文件,完成后将新版本重命名为旧文件名,自动覆盖它。第二个操作称为重命名覆盖

现在,一些参考:

答案3

这让我想起刷新时分配。当文件系统使用此功能时,它不是直接将数据写入磁盘,而是从磁盘的可用空间计数器中​​减去要写入的数据的大小,并将数据保存在内存中,直到执行同步系统调用或内核决定刷新脏缓冲区。

在这种情况下,如果文件正在被一个进程修改,并被另一个进程打开,则后一个进程将“看到”未修改的(或“旧”(如果您愿意)) 文件的版本。

当然,以上是理论上的,取决于各种因素,我想说有点不可预测 - 因为你不知道内核何时会刷新脏页。例如在 Linux 中(您还可以阅读《理解 Linux 内核》的 15.3 节),脏页在以下条件下被写入磁盘:

  • 页面缓存太满,需要更多页面,或者脏页面数量变得太大。

  • 自从页面保持脏状态以来已经过去了太多时间。

  • 进程请求刷新块设备或特定文件的所有挂起更改;它通过调用sync()、fsync()或fdatasync()系统调用来实现这一点。

已知此功能已在 HFS+、XFS、Reiser4、ZFS、Btrfs 和 ext4 文件系统中实现。

相关内容