是否可以对C ++中的类进行序列化和反序列化?
我已经使用Java 3年了,在这种语言中,序列化/反序列化是相当琐碎的。C ++是否具有类似的功能?是否有处理序列化的本机库?
一个例子会有所帮助。
是否可以对C ++中的类进行序列化和反序列化?
我已经使用Java 3年了,在这种语言中,序列化/反序列化是相当琐碎的。C ++是否具有类似的功能?是否有处理序列化的本机库?
一个例子会有所帮助。
Answers:
该Boost::serialization
库处理这个相当典雅。我已经在几个项目中使用过它。这里有一个例子程序,说明如何使用它,在这里。
唯一的本地方法是使用流。这实际上是Boost::serialization
库的全部工作,它通过设置框架将对象写为类似文本的格式并从相同格式读取它们来扩展stream方法。
对于内置类型,或您自己的类型operator<<
并operator>>
正确定义的类型,这非常简单;有关更多信息,请参见C ++常见问题解答。
我意识到这是一篇很旧的文章,但这是搜索时出现的第一篇文章c++ serialization
。
我鼓励任何有权使用C ++ 11的人看一看谷类食品,即用于序列化的仅C ++ 11标头库,支持开箱即用的二进制,JSON和XML。谷物的设计易于扩展和使用,语法与Boost类似。
升压是一个很好的建议。但是,如果您想自己动手,这并不难。
基本上,您只需要一种构建对象图并将其输出为某种结构化存储格式(JSON,XML,YAML等)的方法。建立图形就像使用标记递归体面对象算法然后输出所有标记对象一样简单。
我写了一篇文章,描述了基本的(但仍然功能强大)序列化系统。您可能会发现它很有趣:使用SQLite作为磁盘文件格式,第2部分。
就“内置”库而言,<<
和>>
已专门为序列化保留。
您应该重写<<
以将您的对象输出到某个序列化上下文(通常是iostream
),并>>
从该上下文中读回数据。每个对象负责输出其聚合的子对象。
只要您的对象图不包含循环,此方法就可以正常工作。
如果是这样,那么您将不得不使用一个库来处理这些循环。
<<
运算符用于打印对象的人类可读文本表示形式,而这通常不是序列化所需的内容。
<<
为泛型ostream
定义,请尝试为文件流定义它。
<<
以将您的对象输出到某个序列化上下文……每个对象都负责输出它的……” —问题在于如何避免必须为每个对象繁琐地写出来:语言或图书馆有帮助吗?
我建议使用Google 协议缓冲区。我有机会在一个新项目上测试库,并且非常易于使用。该库针对性能进行了大量优化。
Protobuf与此处提到的其他序列化解决方案不同,因为Protobuf不会序列化您的对象,而是为根据您的规范进行序列化的对象生成代码。
Boost :: serialization是一个不错的选择,但是我遇到了一个新项目:谷物,我发现它更加优雅!我强烈建议您调查一下。
//Create a new AMEF object
AMEFObject *object = new AMEFObject();
//Add a child string object
object->addPacket("This is the Automated Message Exchange Format Object property!!","adasd");
//Add a child integer object
object->addPacket(21213);
//Add a child boolean object
object->addPacket(true);
AMEFObject *object2 = new AMEFObject();
string j = "This is the property of a nested Automated Message Exchange Format Object";
object2->addPacket(j);
object2->addPacket(134123);
object2->addPacket(false);
//Add a child character object
object2->addPacket('d');
//Add a child AMEF Object
object->addPacket(object2);
//Encode the AMEF obejct
string str = new AMEFEncoder()->encode(object,false);
用Java解码就像
string arr = amef encoded byte array value;
AMEFDecoder decoder = new AMEFDecoder()
AMEFObject object1 = AMEFDecoder.decode(arr,true);
协议实现具有适用于C ++和Java的编解码器,有趣的是它可以保留名称/值对形式的对象类表示形式,当我偶然偶然发现该协议时,我在上一个项目中需要一个类似的协议根据我的要求修改了基础库。希望对您有帮助。
我建议按照其他海报所述使用升压序列化。这是有关如何使用它的很好的详细教程,很好地补充了Boost教程:http : //www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/
这是我敲的一个简单的序列化程序库。它仅是c11的标头,并包含用于序列化基本类型的示例。这是一张上课的地图。
https://github.com/goblinhack/simple-c-plus-plus-serializer
#include "c_plus_plus_serializer.h"
class Custom {
public:
int a;
std::string b;
std::vector c;
friend std::ostream& operator<<(std::ostream &out,
Bits my)
{
out << bits(my.t.a) << bits(my.t.b) << bits(my.t.c);
return (out);
}
friend std::istream& operator>>(std::istream &in,
Bits my)
{
in >> bits(my.t.a) >> bits(my.t.b) >> bits(my.t.c);
return (in);
}
friend std::ostream& operator<<(std::ostream &out,
class Custom &my)
{
out << "a:" << my.a << " b:" << my.b;
out << " c:[" << my.c.size() << " elems]:";
for (auto v : my.c) {
out << v << " ";
}
out << std::endl;
return (out);
}
};
static void save_map_key_string_value_custom (const std::string filename)
{
std::cout << "save to " << filename << std::endl;
std::ofstream out(filename, std::ios::binary );
std::map< std::string, class Custom > m;
auto c1 = Custom();
c1.a = 1;
c1.b = "hello";
std::initializer_list L1 = {"vec-elem1", "vec-elem2"};
std::vector l1(L1);
c1.c = l1;
auto c2 = Custom();
c2.a = 2;
c2.b = "there";
std::initializer_list L2 = {"vec-elem3", "vec-elem4"};
std::vector l2(L2);
c2.c = l2;
m.insert(std::make_pair(std::string("key1"), c1));
m.insert(std::make_pair(std::string("key2"), c2));
out << bits(m);
}
static void load_map_key_string_value_custom (const std::string filename)
{
std::cout << "read from " << filename << std::endl;
std::ifstream in(filename);
std::map< std::string, class Custom > m;
in >> bits(m);
std::cout << std::endl;
std::cout << "m = " << m.size() << " list-elems { " << std::endl;
for (auto i : m) {
std::cout << " [" << i.first << "] = " << i.second;
}
std::cout << "}" << std::endl;
}
void map_custom_class_example (void)
{
std::cout << "map key string, value class" << std::endl;
std::cout << "============================" << std::endl;
save_map_key_string_value_custom(std::string("map_of_custom_class.bin"));
load_map_key_string_value_custom(std::string("map_of_custom_class.bin"));
std::cout << std::endl;
}
输出:
map key string, value class
============================
save to map_of_custom_class.bin
read from map_of_custom_class.bin
m = 2 list-elems {
[key1] = a:1 b:hello c:[2 elems]:vec-elem1 vec-elem2
[key2] = a:2 b:there c:[2 elems]:vec-elem3 vec-elem4
}
我正在使用以下模板来实现序列化:
template <class T, class Mode = void> struct Serializer
{
template <class OutputCharIterator>
static void serializeImpl(const T &object, OutputCharIterator &&it)
{
object.template serializeThis<Mode>(it);
}
template <class InputCharIterator>
static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
{
return T::template deserializeFrom<Mode>(it, end);
}
};
template <class Mode = void, class T, class OutputCharIterator>
void serialize(const T &object, OutputCharIterator &&it)
{
Serializer<T, Mode>::serializeImpl(object, it);
}
template <class T, class Mode = void, class InputCharIterator>
T deserialize(InputCharIterator &&it, InputCharIterator &&end)
{
return Serializer<T, Mode>::deserializeImpl(it, end);
}
template <class Mode = void, class T, class InputCharIterator>
void deserialize(T &result, InputCharIterator &&it, InputCharIterator &&end)
{
result = Serializer<T, Mode>::deserializeImpl(it, end);
}
这T
是您要序列化Mode
的类型,是一种虚拟类型,用于区分不同类型的序列化,例如。相同的整数可以序列化为little endian,big endian,varint等。
默认情况下,Serializer
委托将任务委托给要序列化的对象。对于内置类型,您应该对进行模板专用化Serializer
。
还提供了便利功能模板。
例如无符号整数的Little Endian序列化:
struct LittleEndianMode
{
};
template <class T>
struct Serializer<
T, std::enable_if_t<std::is_unsigned<T>::value, LittleEndianMode>>
{
template <class InputCharIterator>
static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
{
T res = 0;
for (size_t i = 0; i < sizeof(T); i++)
{
if (it == end) break;
res |= static_cast<T>(*it) << (CHAR_BIT * i);
it++;
}
return res;
}
template <class OutputCharIterator>
static void serializeImpl(T number, OutputCharIterator &&it)
{
for (size_t i = 0; i < sizeof(T); i++)
{
*it = (number >> (CHAR_BIT * i)) & 0xFF;
it++;
}
}
};
然后进行序列化:
std::vector<char> serialized;
uint32_t val = 42;
serialize<LittleEndianMode>(val, std::back_inserter(serialized));
反序列化:
uint32_t val;
deserialize(val, serialized.begin(), serialized.end());
由于抽象的迭代器逻辑,它应与任何迭代器(例如流迭代器),指针等一起使用。