覆盖文件而不会有文件损坏的风险

Wil*_*ill 5 c++ linux windows file-io

我的应用程序经常想要保存文件以便稍后再次加载。最近不幸发生了崩溃,我想以这样的方式编写操作,以保证我要么拥有新数据,要么拥有原始数据,但没有损坏的混乱。

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

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

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

  • 如果没有“example.dat”并且没有“example.dat.tmp”,则首先运行/新项目,因此加载默认值/创建新文件。
  • 如果“example.dat”且没有“example.dat.tmp”,则加载 example.dat(正常负载情况)
  • 如果“example.dat.tmp”存在,则为用户提供潜在恢复数据的机会。如果“example.dat”也存在,则在没有显式用户常量的情况下不要覆盖它。

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

我不确定磁盘问题实际上可以通过应用程序解决,但是上面的一般规则是否正确?我是否应该保留文件的旧恢复副本更长时间才能确定,有关此类事情的准则是什么(例如可接受的磁盘使用情况,用户是否应该选择,将此类文件放在何处等)。

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

Jam*_*nze 2

如果磁盘驱动器向操作系统报告数据物理上位于磁盘上,但事实并非如此,那么您对此无能为力。许多磁盘确实会缓存一定数量的写入,并报告它们已完成,但此类磁盘应该有备用电池,并无论如何完成物理写入(并且在系统崩溃时它们不会丢失数据,因为他们甚至不会看到它)。

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