序列化是指将数据从有结构清晰的语言定义的数据形式转化为二进制字符串,反序列化则是序列化的逆操作。
百度百科定义序列化如下:
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
关于序列化,其实在MapBox中就已经有雏形。MapBox的作法是使用map
最近翻了翻MapBox,序列化与反序列化的想法又冒了出来。Protocol Buffer的话,需要调用谷歌自己的编译程序(把rule编译为header),感觉比较麻烦(不过比其他的工具简单不少了)。Boost库的话,序列化倒是很方便,但是看了源码之后发现各种模板暂时理解不能... 所以还是想自己写一个小东西试一试。
于是就有了这么个东西 ( View Source On GitHub )
/** Templates */
template
string serialize(const T& a)
{
return T::serialize(a);
}
template
int deserialize(string str,T& a)
{
return T::deserialize(str,a);
}
这里是序列化以及反序列化的通用方法。其实就是调用了一下T类型的序列化和反序列化函数。
/** Special Version
* For...
* int, double, float
*/
/// int
template<>
string serialize(const int& a)
{
string ans;
int c=htonl(a);
ans.append((const char*)&c,sizeof(c));
return ans;
}
template<>
int deserialize(string str,int& c)
{
memcpy(&c,str.data(),sizeof(c));
c=ntohl(c);
return sizeof(c);
}
上面是针对int的特化,进行了字节序的转换
/// string
template<>
string serialize(const string& a)
{
int len=a.size();
string ans;
ans.append(::serialize(len));
ans.append(a);
return ans;
}
template<>
int deserialize(string str,string& a)
{
int len;
::deserialize(str,len);
a=str.substr(sizeof(len),len);
return sizeof(int)+len;
}
以上是针对string的特化,在序列化最前面加入了长度。之前没有这一个长度,结果string和string相连的时候出现了比较棘手的问题......
/// Marco definition
#define NORMAL_DATA_SERIALIZE(Type) template<> \
string serialize(const Type& a) \
{ \
string ans; \
ans.append((const char*)&a,sizeof(a)); \
return ans; \
}
#define NORMAL_DATA_DESERIALIZE(Type) template<> \
int deserialize(string str,Type& a)\
{ \
memcpy(&a,str.data(),sizeof(a)); \
return sizeof(a); \
}
/// double
NORMAL_DATA_SERIALIZE(double);
NORMAL_DATA_DESERIALIZE(double);
NORMAL_DATA_SERIALIZE(float);
NORMAL_DATA_DESERIALIZE(float);
NORMAL_DATA_SERIALIZE(char);
NORMAL_DATA_DESERIALIZE(char);
double与char,视为POD+无字节序问题的类型
template
class Serializable
{
public:
static SerializableType deserialize(string);
static string serialize(const SerializableType& a);
};
可序列化模板类,如果某个类型希望能够序列化,那么应该继承这个类并实现其中的两个方法。
class OutEngine
{
public:
template
OutEngine& operator << (SerializableType& a)
{
string x=::serialize(a);
os.write(x.data(),x.size());
return *this;
}
string str()
{
return os.str();
}
void set_empty()
{
os.str("");
}
OutEngine():os(std::ios::binary){}
public:
ostringstream os;
};
一个输出引擎,使用方法大概就是声明 OutEngine oe;int a=3;然后oe<class InEngine
{
public:
InEngine(string s) : is(s){n_size=leftsize();}
template
InEngine& operator >> (SerializableType& a)
{
int ret=::deserialize(is,a);
is=is.substr(ret);
return *this;
}
void set_str(string s)
{
is=s;
n_size=leftsize();
}
int leftsize()
{
return is.size();
}
int donesize()
{
return n_size-leftsize();
}
protected:
string is;
int n_size;
};
一个输入引擎,原来使用istringstream,后来就直接换成了string,配合substr
测试代码如下
注: 三个成员设计为public是因为方便main里面的代码
class cbox : public Serializable
{
public:
int a;
double b;
string str;
static string serialize(const cbox& inc)
{
OutEngine x;
x<>box.a>>box.b>>box.str;
return x.donesize();
}
};
int main()
{
cbox box;
box.a=11;
box.b=6.6;
box.str="Hello World";
cbox box3;
box3.a=33;
box3.b=12.5;
box3.str="Yummy Hamburger!";
OutEngine oe;
oe<>box2>>box4;
cout<
输出内容(二进制字串在不同设备上的输出应该是不同的,但是内容应该是一致的)