【问题标题】:Adequetely safe method of overwriting a save file?覆盖保存文件的安全方法?
【发布时间】:2013-08-18 03:03:13
【问题描述】:

使用cstdio,覆盖文件最安全的方法是什么?在这种情况下,“安全”意味着文件不可能变得不完整或损坏;该文件将被完全覆盖,或者如果出现问题,它将是旧文件。

我想最好的方法是创建一个临时中间文件,然后在该中间文件完成后覆盖旧文件。如果这实际上是最好的方法,那么还有一些其他问题似乎是可能的,尽管很少见。

  • 如果程序在覆盖时退出,我怎么知道使用这个其他文件?
  • 如果程序在创建期间退出,我怎么知道不使用其他文件?
  • 我怎么知道原始文件或 中间处于未定义状态(因为它可能会以某种方式失败 仍然可读,但它包含的数据有细微的错误)?

我想这有一个好的做法,但我一直找不到。这是用于保存的游戏数据;只有一个文件,而且每次都会覆盖整个文件,不用担心部分覆盖或追加。

【问题讨论】:

  • 不要覆盖它。选择另一个名字。如果可行,则重命名文件。
  • @HansPassant 这似乎正是第二段所建议的,尽管术语不准确。
  • @HansPassant 阅读 rename() 上的文档,它提到如果新名称已经存在,则操作可能会失败或成功,这取决于实现。
  • 我把它写在this answer。如果您在 Windows 中执行此操作,则可以使用 ReplaceFile()。

标签: c++ file save


【解决方案1】:

正如其他人所说,保留现有文件并写入新文件。如果它非常重要(即用户不可能恢复信息),请确保周围还有一个“备份”文件(例如,如果您的程序保存了abc.config,请留下abc.old.config 或@987654323 @ [如果你想保证这个名字在任何地方都有效,.cfg.bak 可能是更好的选择])。

当你写文件的时候,在文件中加入某种结束标记,这样你就可以确定文件是完整的。如果您想避免“用户编辑”文件,您可能还需要内容的校验和(sha1、md5 或类似)。如果 endmarker 不存在,或者校验和错误,那么你就知道文件是“坏的”,所以不要使用它。去备份。

  1. 将新内容写入临时文件(例如fstream fout("abc.tmp");
  2. 删除备份文件(如果存在)(例如remove("abc.bak");
  3. 将现在的旧文件重命名为备份名称(例如rename("abc.cfg", "abc.bak");
  4. 将新文件重命名为旧文件(例如rename("abc.tmp", "abc.cfg");

对于所有步骤(尤其是写入实际数据),检查错误。您需要决定哪里可以出错,哪里不能出错(例如,不存在的文件的remove 可以,但是如果rename 不起作用,您可能应该停止,或者您可能会导致一些不好的事情)。

加载文件时,检查所有步骤,如果出错,返回备份文件。

【讨论】:

  • 我想知道 Windows 文件重命名是否在返回之前“刷新”到磁盘。如果没有,那么保存后的电源故障可能会“回滚”您保存的文件。我会假设它保证“冲洗”,但我找不到任何提及它。
  • 我不是 100% 确定(当然,有些磁盘可能不会真正刷新到磁盘,即使他们说有!),但我希望重命名是原子的,因为它要么完成,要么根本没有完成。
  • 除非我遗漏了什么,否则重命名已经完成并因此完成,或者旧文件应该仍然存在,假设操作系统没有在它的“重命名”中做一些愚蠢的事情,比如“删除旧文件名(flush),放入新文件名(flush)”以一种没有创建“新文件名”但删除旧文件名的方式 - 这将是完全疯狂的。
  • 如果在第 3 步后崩溃了怎么办?那么可能所有数据都在磁盘上,但是没有abc.cfg
  • 是的,但是数据还在,没有丢失。除非我们谈论的是 SYSTEM 崩溃,否则如果经过正确测试,您的应用程序不应在此位置崩溃。但是,最初的问题是关于“如何确保文件本身完整或未使用” - 换句话说,文件本身没有“一半的信息,一半丢失”,上面充分解决了这个问题。
【解决方案2】:

您应该在将数据保存到文件时阻止应用程序关闭。您应该做的是加载旧文件,将其保存在变量中 - 覆盖变量的数据(在您的应用程序中),然后将其覆盖旧文件。 一切都应该不到 1 秒,因此您不必担心在保存时关闭应用程序。 另外,只有在检查操作是否可行并且数据的完整性是否正确后才进行覆盖。

【讨论】:

  • 您无法阻止应用程序被关闭。 “一切都应该花费不到 1 秒”是推测性的,因为您不知道文件的大小。
【解决方案3】:

您应该为此使用保证 ACID 的数据库管理系统。如果您坚持使用平面文件,则应写入临时文件,写入完成后复制并替换实际文件,仅在复制成功时删除临时文件。此外,在每次写入文件时调用flush()

【讨论】:

  • 由于临时文件是为了以防程序在保存过程中死机,一旦程序备份并查看文件,判断是否以及何时发生故障的最佳方法是什么,以便可以改正吗?
  • 您应该知道临时文件的名称(例如 program.file)。你的程序应该检查文件是否存在,如果文件存在,做一些事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
相关资源
最近更新 更多