在不存在文件损坏风险的情况下覆盖文件

Overwriting a file without the risk of a corrupt file

本文关键字:文件 情况下 覆盖 不存在 损坏      更新时间:2023-10-16

我的应用程序经常希望保存文件以便以后再次加载。由于最近遭遇了一次崩溃,我想以这样一种方式编写操作,即保证我既有新数据,也有原始数据,但不会出现损坏的混乱。

我的第一个想法是按照以下行做一些事情(保存一个名为example.dat的文件):

  1. 为目标目录提供一个唯一的文件名,例如example.dat.tmp
  2. 创建那个文件并将我的数据写入其中
  3. 删除原始文件(例如.dat)
  4. 将临时文件重命名("移动")到原始文件所在的位置(example.dat.tmp->example.dat)

然后在加载时,应用程序可以遵循以下规则:

  • 如果没有"example.dat"answers"example.dat.tmp",则首先运行/new项目,因此在默认值中加载/create new文件
  • 如果"example.dat"而没有"example.dat.tmp",则加载example.dat(正常加载情况)
  • 如果存在"example.dat.tmp",则为用户提供可能恢复数据的机会。如果"example.dat"也存在,请不要在没有显式用户常量的情况下覆盖它

然而,在做了一点研究后,我发现,除了我可以用文件刷新方法覆盖的操作系统缓存外,一些磁盘驱动器仍然在内部缓存,甚至可能对操作系统撒谎说它们已经完成了,所以4。可以完成,写入实际上并没有写入,如果系统出现故障,我就丢失了数据。。。

我不确定磁盘问题是否真的可以通过应用程序解决,但上面的一般规则是正确的吗?我是否应该保留文件的旧恢复副本更长的时间来确定,关于这些事情的指导方针是什么(例如,可接受的磁盘使用,用户应该选择,将这些文件放在哪里,等等)

此外,我应该如何避免用户和其他程序之间的潜在冲突,例如"example.dat.tmp"。我记得有时在其他软件中看到过"~example.dat",这是更好的约定吗?

如果磁盘驱动器向操作系统报告数据物理地在磁盘上,而不是,那么你就没有多少可以。很多磁盘确实缓存了一定数量的写入,并报告它们已完成,但这样的磁盘应该电池备份,并完成物理写入(在系统崩溃的情况下,他们不会丢失数据,因为甚至看不到)。

剩下的,你说你已经做了一些研究,所以你毫无疑问要知道,不能使用std::ofstream(也不能使用FILE*);您必须在系统级别进行实际写入,然后打开具有特殊属性的文件,以确保完整同步。否则,操作可能会在OS缓冲一段时间。据我所知,没有办法确保CCD_ 3的这种同步。(但我不确定是否有必要,如果你总是留两个版本:在这种情况下,我通常会写信给一个文件"example.dat.new",然后当我写完后,删除任何名为"example.dat.bak"的文件,将"example.dat"重命名为"example.dat.bak",然后将"example.dat.new"重命名为"example.dat"。考虑到这一点,你应该能够弄清楚发生了什么或没有发生什么,并找到正确的文件(如果需要的话,以交互方式插入,或者插入一个带有时间戳)。

如果不同的进程可能通过您所描述的相同协议,则在编写替代文件时应锁定实际的数据文件。

您可以使用flock进行文件锁定。

至于临时文件名,您可以将进程ID作为其中的一部分,例如"example.dat.3124",没有其他同时运行的进程会生成相同的名称。

相关文章: