C++序列化与反序列化的简单探索

序列化是指将数据从有结构清晰的语言定义的数据形式转化为二进制字符串,反序列化则是序列化的逆操作。

百度百科定义序列化如下:

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。


关于序列化,其实在MapBox中就已经有雏形。MapBox的作法是使用map<string,string>作为底层容器,第一元素为 Tag标签,第二元素为 Context内容。方法toString()能够将MapBox转化为一个字符串,这个过程中MapBox是使用base64编码+特殊字符实现的。MapBox没有提供反序列化方法,只是在通过网络接收数据的时候能够 将字符串解析为MapBox。(毕竟MapBox的设计初衷就是网络编程,起初打算打造一个MapBox over socket的东西...,但是发现base64本身存在的缺点在数据量暴涨的时候大于base64的优点,于是放弃了MapBox over socket的设计。但是现在MapBox在传输不超过200MB的内容时仍然具有较好的表现)

最近翻了翻MapBox,序列化与反序列化的想法又冒了出来。Protocol Buffer的话,需要调用谷歌自己的编译程序(把rule编译为header),感觉比较麻烦(不过比其他的工具简单不少了)。Boost库的话,序列化倒是很方便,但是看了源码之后发现各种模板暂时理解不能... 所以还是想自己写一个小东西试一试。

于是就有了这么个东西 ( View Source On GitHub )

/** Templates */
template<typename T>
string serialize(const T& a)
{
    return T::serialize(a);
}

template<typename T>
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); \
    }

针对POD而且不需要字节序转换的宏定义


/// 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<typename SerializableType>
class Serializable
{
public:
    static SerializableType deserialize(string);
    static string serialize(const SerializableType& a);
};
可序列化模板类,如果某个类型希望能够序列化,那么应该继承这个类并实现其中的两个方法。


class OutEngine
{
public:
    template<typename SerializableType>
    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<<a; 调用oe.str()来获取序列化字串


class InEngine
{
public:
    InEngine(string s) : is(s){n_size=leftsize();}
    template<typename SerializableType>
    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<cbox>
{
public:
    int a;
    double b;
    string str;

    static string serialize(const cbox& inc)
    {
        OutEngine x;
        x<<inc.a<<inc.b<<inc.str;
        return x.str();
    }
    static int deserialize(string inc,cbox& box)
    {
        InEngine x(inc);
        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<<box<<box3;

    string b=oe.str();
    cout<<b<<endl;

    cbox box2;
    cbox box4;
    InEngine ie(b);
    ie>>box2>>box4;

    cout<<box2.a<<endl;
    cout<<box2.b<<endl;
    cout<<box2.str<<endl;

    cout<<box4.a<<endl;
    cout<<box4.b<<endl;
    cout<<box4.str<<endl;
    return 0;
}

输出内容(二进制字串在不同设备上的输出应该是不同的,但是内容应该是一致的)



C++中,序列化是指将对象的状态信息转换为可以存储或传输的形式的过程,而反序列化则是将存储或传输形式的数据恢复为对象状态的过程。 一个简单C++序列化反序列化的代码示例可以使用C++标准库中的iostream和fstream来完成。下面是一个简单的例子,展示了一个Point类的序列化反序列化过程: ```cpp #include <iostream> #include <fstream> #include <string> // 一个简单的Point类用于示例 class Point { public: int x, y; Point(int x = 0, int y = 0) : x(x), y(y) {} // 序列化函数 void serialize(std::ostream& out) { out.write(reinterpret_cast<const char*>(&x), sizeof(x)); out.write(reinterpret_cast<const char*>(&y), sizeof(y)); } // 反序列化函数 void deserialize(std::istream& in) { in.read(reinterpret_cast<char*>(&x), sizeof(x)); in.read(reinterpret_cast<char*>(&y), sizeof(y)); } }; int main() { Point p(10, 20); std::ofstream outFile("point.bin", std::ios::binary); p.serialize(outFile); // 将p序列化到文件 outFile.close(); Point p2; std::ifstream inFile("point.bin", std::ios::binary); p2.deserialize(inFile); // 从文件反序列化p2 std::cout << "Deserialized point: (" << p2.x << ", " << p2.y << ")" << std::endl; inFile.close(); return 0; } ``` 这段代码首先定义了一个Point类,其中包含了x和y两个成员变量,并提供了serialize和deserialize两个成员函数用于序列化反序列化序列化函数将对象的状态写入到一个输出流中,而反序列化函数从输入流中读取状态并恢复对象。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值