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

标签 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”,这是更好的约定吗?

最佳答案

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

剩下的,你说你做了一些研究,所以你毫无疑问 知道您不能为此使用 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/

相关文章:

c++ - 尝试引用已删除函数的唯一指针

linux - Systemd ExecStart 中的 Bash 大括号扩展

linux - 将域指向托管服务器文件夹时出现问题

sql-server - 为什么这个带有 DBI 连接到 MS SQL 服务器的 perl 程序通过 ODBC 泄漏内存?

c++ - 如何注册 Windows 类并使用已注册的类查找窗口

c++ - 适用于 Windows 的 Helgrind?

c++ - VS2017 15.7.3 C++ Document Format 重排行导致编译错误

C++11 没有匹配函数来调用‘std::vector

python - 使 Python 脚本与 linux 包相结合,易于最终用户安装

用于验证相等运算符的 C++ 测试随着时间的推移与结构保持一致