【问题标题】:Managing changes in memory-based data format管理基于内存的数据格式的更改
【发布时间】:2011-01-11 17:38:34
【问题描述】:

所以我一直在 c++ 中使用紧凑型数据类型,从内存中保存或从文件中加载只涉及将内存位复制进出。

但是,这样做的明显缺点是,如果您需要在数据上添加/删除元素,它会变得有点混乱。版本控制也有问题,假设您分发的程序使用版本 A 的数据,然后第二天制作版本 B,然后再制作版本 C。

我想这可以通过使用 xml 或 json 之类的东西来解决。但是假设由于技术原因您不能这样做。

除了必须做出不同的 if 案例等(我想这会很丑陋)之外,最好的方法是什么

【问题讨论】:

  • 你是指不同版本的data,还是type
  • 不同版本的数据。实际上,omnitarius 认为它​​与协议缓冲区完全相同。

标签: c++ data-structures file-format


【解决方案1】:

我不知道您的“技术原因”是什么,但如果它们涉及速度或数据大小,那么我可能会建议 Protocol Buffers 作为您的解决方案。它明确设计用于处理版本控制。它会比简单地转储一个结构稍微慢一点,稍微大一点,但只是稍微大一点,而且它会更便携并且更好地处理版本控制。

【讨论】:

  • 嗯,是的,这很好。我可能会调查一下,谢谢!
【解决方案2】:

来自 3dsmax 的一个想法(如果我没记错的话):将文件分成块,每个块都有一个标题(可能是长的)描述它和一个 长度。阅读时,如果您不知道标题,则通过知道 len 跳到下一个。这个过程在每个块内部递归应用,并确保向后兼容。

【讨论】:

  • 这听起来像是 Protocol Buffers 为您所做的。 :-)
  • 有趣,很高兴知道,实际上我使用了 CSharp 语言的 protobuff 的实现,但我没有看太多内部 ;)
【解决方案3】:

如果你走“面向列”的方式,那么你可以随意添加字段。

旧方式的原始结构:

struct Person {
  string name;
  int age;
};

vector<Person> People;  // single file for all fields

用旧方法添加字段:

struct Person {
  string name;
  int age;
  string address;  // now must rewrite files on disk
};

新的和改进的方式:

namespace People {
  vector<string> name;  // first file
  vector<int> age;      // second file
}

添加到新的方式:

namespace People {
  vector<string> name;
  vector<int> age;
  vector<string> address;  // add a third file and leave other two alone 
}

要点是每个字段都是它自己的文件。额外的好处是用户只需要读/写他想要的字段,因此版本控制变得更容易。

【讨论】:

  • 作为用户,如果你这样做,我会恨你的。必须复制大量文件才能进行简单备份非常烦人。
  • @Billy 为了进行简单的备份而不得不复制大量文件非常烦人。 OP 有什么不同之处?
  • @chrisaycock:OP 正在使用单个文件。
  • 这也是非常脆弱的,因为它取决于所有文件中的记录号是否准确排列。
  • @Omnifarious 这个简单的例子确实有这个缺点,是的。面向列的商业数据库(如 Kx)根据其他字段(如日期)对文件进行分区。这样,用户可以为不同的日期添加一个新字段,并告诉数据库只从未来的新日期中进行选择。这让一切都排成一列。
【解决方案4】:

我们在工作中处理这个问题。这不是最好的,但您可以做一些事情:

  • 为所有文件添加一个标题,第一个字段为“版本”,第二个字段为“长度”。在加载时,您现在可以适当地处理旧版本。

  • 如果可以,请制定规则“从不删除数据字段,始终在文件末尾添加字段”。如果你这样做,那么你的加载代码可以加载一个旧的、更短的版本文件,只需将可用数据读入结构并保持最后一个字段(不在文件中)初始化。当您开始拥有结构数组时,这会分崩离析,此时您需要手动加载数据。

【讨论】:

    【解决方案5】:

    这就是 将如何破解它。这是一种“hacky”方法,但可以扩展为更复杂。

    struct file
    {
     int32 fileversion;    //different parsers, one for each file version
     int offsetlen;        //length of blocks
     int numblocks;        //number of blocks
     int*  fileoffsets;    //this array has internal offsets, corresponding to blocks
     block* blocklist;     //blocks.
    };
    
    struct block
    {
      //stuff here of a fixed length
    };
    

    要写入具有固定大小块的文件,算法应该是这样的 -

    write(f.fileversion)
    write(f.offsetlen)
    write(f.numblocks)
    for i in f.blocklist
      write(f.blocklist[i])
    

    和阅读 -

    f.fileversion = read(sizeof(f.fileversion))
    f.offsetlen = read(sizeof(f.offsetlen))
    f.numblocks = read(sizeof(f.numblocks))
    for i in f.numblocks
       f.blocks[i] = read(f.offsetlen)
    

    对于异构块,您​​需要在阅读时跟踪偏移量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-15
      • 2019-06-17
      • 2018-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多