覆盖文件没有损坏的文件的风险

所以经常我的应用程序想保存文件以后再加载。 最近因为崩溃而倒霉了,我想以这样一种方式编写操作,即保证有新的数据或原始数据,但不会有混乱。

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

  1. 为目标目录提供一个唯一的文件名,例如example.dat.tmp
  2. 创build该文件并写入我的数据。
  3. 删除原始文件(example.dat)
  4. 重命名(“移动”)临时文件到原来的位置(example.dat.tmp – > example.dat)。

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

  • 如果没有“example.dat”而没有“example.dat.tmp”,首先运行/新build项目,这样就加载默认/新build文件。
  • 如果“example.dat”没有“example.dat.tmp”,则加载example.dat(正常载入大小写)
  • 如果存在“example.dat.tmp”,则为用户提供潜在恢复数据的机会。 如果还存在“example.dat”,则不要在没有明确的用户常量的情况下覆盖它。

但是,我做了一些小小的研究后发现,除了操作系统caching(我可以用文件刷新方法覆盖)之外,有些磁盘驱动器仍然可以在内部caching,甚至可能对操作系统说谎,因此4可以完成,写入不实际写入,如果系统closures,我已经丢失了我的数据…

我不确定磁盘问题实际上是由应用程序解决的,但是正确的事情上面的一般规则是? 我应该保留一个旧的文件恢复副本,以确保更长的时间,有关这些事情的指导方针是什么(例如,可接受的磁盘使用情况,用户应该select,放置这些文件的位置等)。

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

Solutions Collecting From Web of "覆盖文件没有损坏的文件的风险"

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

其余的,你说你已经做了一些研究,所以你毫无疑问知道你不能使用std::ofstream (也不是FILE* )。 您必须在系统级别进行实际的写入操作,并打开具有特殊属性的文件以确保完全同步。 否则,操作可能会在操作系统缓存一段时间。 而据我所知,没有办法确保rename同步。 (但是我不确定是否有必要,如果你总是保留两个版本:在这种情况下,我惯常的约定是写一个文件"example.dat.new" ,然后当我写完后,删除任何名为"example.dat.bak" ,将"example.dat"重命名为"example.dat.bak" ,然后将"example.dat.new"重命名为"example.dat" ,这样就可以搞清楚了发生了什么或没有发生什么,并找到正确的文件(如果需要,可以交互式地输入,或者插入带有时间戳的起始行)。

如果有可能不同的进程可能会通过您所描述的相同协议,那么您应该在写入其替代品时锁定实际的数据文件。

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

至于你的临时文件名,你可以使你的进程ID成为它的一部分,例如“example.dat.3124”,没有其他同时运行的进程会生成相同的名字。