我的应用程序经常想要保存文件以便稍后再次加载。最近因崩溃而倒霉,我想以这样一种方式编写操作,以保证我拥有新数据或原始数据,但没有损坏的困惑。
我的第一个想法是按照以下方式做一些事情(保存一个名为 example.dat 的文件):
- 为目标目录想出一个唯一的文件名,例如example.dat.tmp
- 创建该文件并将我的数据写入其中。
- 删除原文件(example.dat)
- 将临时文件重命名(“移动”)到原始文件所在的位置(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”,这是更好的约定吗?
最佳答案
如果磁盘驱动器向操作系统报告数据是 物理上在磁盘上,它不是,那么你就没有多少 可以做些什么。很多磁盘确实缓存了一定数量的 写入并报告它们已完成,但是这样的磁盘应该有 备用电池,无论如何都要完成物理写入 (而且他们不会在系统崩溃的情况下丢失数据,因为他们 甚至不会看到它)。
剩下的,你说你做了一些研究,所以你毫无疑问
知道您不能为此使用 std::ofstream
(也不能使用 FILE*
);
您必须在系统级别进行实际写入,然后打开
具有特殊属性的文件,以确保完整
同步。否则,操作可能会停留在
操作系统缓冲了一会儿。据我所知,
没有办法确保 rename
的这种同步。
(但我不确定是否有必要,如果你总是保留两个
版本:在这种情况下,我通常的惯例是写信给
一个文件 "example.dat.new"
,然后当我写完后,删除
任何名为 "example.dat.bak"
的文件,将 "example.dat"
重命名为
"example.dat.bak"
,然后将"example.dat.new"
重命名为
“example.dat”
。鉴于此,您应该能够弄清楚
发生了什么或没有发生什么,并找到正确的文件
(交互地,如果需要的话,或者插入一个初始行
时间戳)。
关于c++ - 覆盖文件而不会有损坏文件的风险,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17884153/