1. 什么是序列化?
在编写应用程序的时候往往需要将某些数据存储在内存中,然后将其写入某个文件或将它传输到网络中的另一台计算机上以实现通讯。这个将程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)。
简单来说,序列化就是将对象实例转换为可存储或传输的数据流的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻松地存储和传输数据。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。
总结
序列化:将对象变成字节流的形式传出去。
反序列化:从字节流恢复成原来的对象。
2. Google Protocol Buffers(protobuf)
Google Protocol Buffers (GPB)是Google内部使用的数据编码方式,旨在用来代替XML进行数据交换。可用于数据序列化与反序列化。主要特性有:
- 高效
- 语言中立(Cpp, Java, Python)
- 可扩展
3. protobuf
在使用过程中要注意两个问题:
(1)支持的数据类型不是很丰富
protobuf属于轻量级的,因此不能支持太多的数据类型,下面是protobuf支持的基本类型列表,一般需求都能满足。
.proto type | c++ | notes |
double | double |
|
float | float |
|
int32 | int32 | 使用可变长编码方式,负数时不够高效,应该使用sint32 |
int64 | int64 | 同上 |
uint32 | uint32 | 使用可变长编码方式 |
uint64 | uint64 | 同上 |
sint32 | int32 | 使用可变长编码方式,有符号的整型值,编码时比通常的int32高效 |
sint64 | sint64 | 同上 |
fixed32 | uint32 | 总是4个字节,如果数值总是比2^28大的话,这个类型会比uint32高效 |
fixed64 | uint64 | 总是8个字节,如果数值总是比2^56大的话,这个类型会比uint64高效 |
sfixed32 | int32 | 总是4个字节 |
sfixed64 | int64 | 总是8个字节 |
bool | bool |
|
string | string | 一个字符串必须是utf-8编码或者7-bit的ascii编码的文本 |
bytes | string | 可能包含任意顺序的字节数据 |
(2)不支持二维数组(指针),不支持STL容器序列化
稍复杂点的数据结构或类结构里出现二维数组、二维指针和STL容器(set、list、map等)很频繁,但因为 protobuf简单的实现机制,只支持一维数组和指针(用repeated修饰符修饰),不能使用repeated repeated来支持二维数组, 也不支持STL。
(3)protobuf嵌套后会改变类名称
protobuf支持类的嵌套,即在一个自定义类型中可以定义另一个自定义类型,但注意嵌套的自定义类型在经过protobuf处理后生成的类名称并不是你定义的类名称,而是加上了外层的类名称作为前缀,下面举一个简单的例子:
message DFA {
required int32 _size = 1;
message accept_pair {
required bool is_accept_state = 1;
required bool is_strict_end = 2;
optional string app_name = 3;
}
repeated accept_pair accept_states = 2;
}
那么嵌套中的accept_pair 生成后的类不是accept_pair 而是DFA_accept_pair 。如果不想改类名称,将accept_pair 拿到外面与DFA平行定义即可。