覆盖文件而不存在文件损坏的风险

时间:2013-07-26 14:33:28

标签: c++ linux windows file-io

因此,我的应用程序通常希望保存文件以便以后再次加载。最近因崩溃而不幸,我想以这样的方式编写操作,以确保我拥有新数据或原始数据,但没有损坏的混乱。

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

  1. 为目标目录提供唯一的文件名,例如: example.dat.tmp
  2. 创建该文件并将数据写入其中。
  3. 删除原始文件(example.dat)
  4. 将临时文件重命名(“移动”)到原始文件的位置(example.dat.tmp - > example.dat)。
  5. 然后在加载时,应用程序可以遵循以下规则:

    • 如果没有“example.dat”而没有“example.dat.tmp”,首先运行/ new project,所以加载默认值/创建新文件。
    • 如果是“example.dat”而没有“example.dat.tmp”,则加载example.dat(正常载荷大小写)
    • 如果“example.dat.tmp”存在,则为用户提供可能恢复数据的机会。如果“example.dat”也存在,则在没有明确的用户常量的情况下不要覆盖它。

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

    我不确定磁盘问题是否可以由应用程序解决,但是正确的规则是否正确?我应该保留文件的旧恢复副本以确保更长时间,有关此类事项的准则是什么(例如,可接受的磁盘使用情况,用户应该选择,放置此类文件的位置等)。

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

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

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

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