我有一组我希望序列化数据的类。但是有很多数据,(我们正在讨论一个带有多达一百万或更多类实例的std :: map)。
不希望过早地优化我的代码,我想我会尝试一个简单而干净的XML实现,所以我使用tinyXML将数据保存到XML,但它太慢了。所以我开始考虑使用Boost.Serialization编写和读取标准ascii或二进制文件。
它似乎更适合于任务,因为在开始之前我不必将所有这些内存分配为开销。
我的问题基本上是如何为文件格式规划最佳序列化策略。如果不是必要的话,我并不特别希望序列化整个地图,因为它实际上只是我追求的内容。已经玩了一些序列化(并查看输出),我不明白如何加载数据可以知道它何时到达地图的末尾,例如,如果我只是一个接一个地保存所有项目。在规划序列化策略时,您需要考虑哪些问题?
感谢。
答案 0 :(得分:4)
阅读此FAQ!这有助于开始吗?
答案 1 :(得分:3)
boost.serialization有许多优点。例如,正如您所说,只包含具有指定签名的方法,允许框架序列化和反序列化您的数据。此外,boost.serialization包括所有标准STL容器的序列化器和读取器,因此您不必担心所有键是否已存储(它们将)或如何在反序列化时检测映射中的最后一个条目(它将是自动检测。)
但是,有一些考虑因素需要考虑。例如,如果您的类中有一个字段用于计算或用于加速,例如索引或哈希表,则不必存储这些字段,但您必须考虑到你必须从磁盘读取的数据重建这些结构。
至于你提到的“文件格式”,我想有时我们会尝试关注格式而不是数据。我的意思是,只要您能够使用(比如说)boost.serialization无缝地检索数据,文件的确切格式就无关紧要了。如果您想与不使用序列化的其他实用程序共享该文件,那就是另一回事。但仅仅出于(反)序列化的目的,您不必关心内部文件格式。
答案 2 :(得分:1)
如果没有必要,我并不特别希望序列化整个地图,因为它实际上只是我追求的内容。
这是否意味着你真的不需要序列化整个对象?也许你应该重新考虑使用基于文本的格式。如果您确实只需要在地图中序列化键/值对的子集,那么您应该将它们写入文本文件并稍后阅读。您不一定需要XML
;每个地图键只有一行,后跟一行,值应该有效。
答案 3 :(得分:1)
如果您想要的只是键值对,那么重要的是键和值所采用的类型,这将为您处理事物的方式着色。
将地图本身序列化通常是一个糟糕的计划,因为您可能希望稍后更改关联容器类型,但不会使先前的序列化文件无效(或必须翻译)。
如果您希望避免再次重建容器的成本,那么序列化容器在某些情况下会很有用(但是预先调整容器大小通常足以避免绝大部分的开销)但这应该是基于决策的关于您的申请和使用的具体方面。
如果您提供键/值的类型,我们可以提供更多帮助。没有这个是一些一般的提示:
答案 4 :(得分:1)
使用Google的Protocol Buffers,这是一种与语言无关,平台无关,可扩展的序列化结构化数据的方式,可用于通信协议,数据存储等。 Google对几乎所有内部RPC协议和文件格式都使用Protocol Buffers。
有C ++,Java,Python,Perl,C#和Ruby的绑定。
您在元数据.proto文件
中描述您的数据message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
}
然后你会在C ++中使用它:
Person person;
person.set_id(123);
person.set_name("Bob");
person.set_email("bob@example.com");
fstream out("person.pb", ios::out | ios::binary | ios::trunc);
person.SerializeToOstream(&out);
out.close();
或者像这样:
Person person;
fstream in("person.pb", ios::in | ios::binary);
if (!person.ParseFromIstream(&in)) {
cerr << "Failed to parse person.pb." << endl;
exit(1);
}
cout << "ID: " << person.id() << endl;
cout << "name: " << person.name() << endl;
if (person.has_email()) {
cout << "e-mail: " << person.email() << endl;
}
有关更完整的示例,请参阅tutorials。