boost之序列化學習(一)

最近在研究boost這個庫,這個庫很強大,鑑於工作的需要,我花了點時間學習了下boost庫裏的序列化機制,個人感覺很強大,boost庫對序列化這塊支持的範圍很廣,其中對於xml這方面的序列化機制感覺支持的很不錯,下面就從最基礎的開始吧,代碼如下:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/list.hpp>
#include <iostream>
#include <fstream>

void save()
{
    std::ofstream file("archive.txt");
    boost::archive::text_oarchive oa(file);
    std::string s = "Hello world";
    //oa << s;
    oa & s;
}

void load()
{
    std::ifstream file("archive.txt");
    boost::archive::text_iarchive ia(file);
    std::string s;
    //ia >> s;
    ia & s;
    std::cout << s << std::endl;
}

在boost中比較常用的序列化機制主要分爲文本時和二進制形式,而文本時的序列化機制又分爲了純文本式和xml式,而上面的例子就是一個純文本式的序列化機制,裏面用到了boost庫的text_oarchive和text_iarchive,並且在用boost做序列化時我們一般都會設置一些序列化載體,純文本式的序列化機制其載體就是單個的純文本文件,而xml式的載體則是xml文件,至於二進制序列化其載體就不確定了,一般都是內存buffer結構,有時也會寫文件,在上述代碼中,我們首先定義好了載體,然後與相應的序列化對象進行關聯,並通過相應的運算符操作來實現相關的序列化操作,接下來,我們來看看xml式的序列化機制,代碼如下:

void save_XML()
{
    std::ofstream file("test.xml");
    boost::archive::xml_oarchive oa(file);
    std::string s = "Hello world";
    oa & BOOST_SERIALIZATION_NVP(s);
}

void load_XML()
{
    std::ifstream file("test.xml");
    boost::archive::xml_iarchive ia(file);
    std::string s;
    ia & BOOST_SERIALIZATION_NVP(s);
    std::cout << s <<std::endl;
}

在以xml爲載體的序列化中,會使用到xml_oarchive和xml_iarchive,並且還會使用到BOOST_SERIALIZATION_NVP這個宏,在這個地方我們先不對這些對象以及宏進行深入討論,在下篇博文中,我們會深入分析boost庫的Serialization這個類,接下來,我們稍微來看看基於xml式序列化機制的一些測試用例吧,代碼如下:

1. 針對數組和STL

void save_Array()
{
    std::ofstream file("test1.xml");
    boost::archive::xml_oarchive oa(file);
    int array1[] = {12,23,34,4,343};
    oa & BOOST_SERIALIZATION_NVP(array1);
}

void load_Array()
{
    std::ifstream file("test1.xml");
    boost::archive::xml_iarchive ia(file);
    int restored[5];
    ia & BOOST_SERIALIZATION_NVP(restored);
    std::ostream_iterator<int> oi(std::cout," ");
    std::copy(restored,restored+5,oi);
}

void save_STL()
{
    std::ofstream file("test2.xml");
    boost::archive::xml_oarchive oa(file);
    int array[] = {23,45,51,23,34,45};
    std::vector<int> vec(array,array+6);
    std::list<int> lst(array,array+6);
    oa & BOOST_SERIALIZATION_NVP(vec);
    oa & BOOST_SERIALIZATION_NVP(lst);
}

void load_STL()
{
    std::ifstream file("test2.xml");
    boost::archive::xml_iarchive ia(file);
    std::list<int> L2;
    ia & BOOST_SERIALIZATION_NVP(L2);
    std::vector<int> V2;
    ia & BOOST_SERIALIZATION_NVP(V2);

    std::ostream_iterator<int> oi(std::cout," ");
    std::copy(L2.begin(),L2.end(),oi);
    std::copy(V2.begin(),V2.end(),oi);
}

其結果:

1)針對數組

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<array1>
    <count>5</count>
    <item>12</item>
    <item>23</item>
    <item>34</item>
    <item>4</item>
    <item>343</item>
</array1>
</boost_serialization>

2)針對STL

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<vec>
    <count>6</count>
    <item_version>0</item_version>
    <item>23</item>
    <item>45</item>
    <item>51</item>
    <item>23</item>
    <item>34</item>
    <item>45</item>
</vec>
<lst>
    <count>6</count>
    <item_version>0</item_version>
    <item>23</item>
    <item>45</item>
    <item>51</item>
    <item>23</item>
    <item>34</item>
    <item>45</item>
</lst>
</boost_serialization>

2. 針對自定義結果序列化

struct date
{
    date()
    {
        year = month = day = 0;
    }
    date(int year,int month,int day)
    {
        this->year = year;
        this->month = month;
        this->day = day;
    }

/*    template<class Archive>
    void serialize(Archive& archive,const unsigned int version)
    {
        //archive & year;
        //archive & month;
        //archive & day;
        archive & BOOST_SERIALIZATION_NVP(year);
        archive & BOOST_SERIALIZATION_NVP(month);
        archive & BOOST_SERIALIZATION_NVP(day);
    }
    */
    int year;
    int month;
    int day;
};
/*
namespace boost
{
    namespace serialization{
        template<class Archive>
        void serialize(Archive& archive,date& data,const unsigned int version)
        {
            archive & BOOST_SERIALIZATION_NVP(data.year);
            archive & BOOST_SERIALIZATION_NVP(data.month);
            archive & BOOST_SERIALIZATION_NVP(data.day);
        }
    }
}*/

在針對自定義結構的序列化中,其有兩種方式來實現對成員的序列化操作,其一:直接在自定義類型中實現serialize這個函數,其二:將serialize實現放置在自定義類型之外,這兩種實現方式分別對應着兩種稱爲:1)入侵式序列化,2)非入侵式序列化,這兩種序列化各有優缺點,使用入侵式序列化需要在結構體中實現serialize函數,這樣就破壞了類的封裝,使用非入侵式序列化,需要將類中的成員變量設置爲public,這樣就對外暴露了類的實現,至於如何取捨,關鍵是在於程序的設計者,結果如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<da class_id="0" tracking_level="0" version="0">
    <data.year>2014</data.year>
    <data.month>2</data.month>
    <data.day>8</data.day>
</da>
</boost_serialization

3. 針對自定義結構的指針序列化

    對自定義結構指針序列化主要是針對指針所指定的實際內容進行序列化,在這方面boost庫Serialization類做的還算不錯,代碼如下:

void save_Pointer()
{
    std::ofstream file("Object3.xml");
    boost::archive::xml_oarchive oa(file);
    date* dat = new date(2014,2,10);
    oa & BOOST_SERIALIZATION_NVP(dat);
}

void load_Pointer()
{
    std::ifstream file("Object3.xml");
    boost::archive::xml_iarchive ia(file);
    date* dr;
    ia & BOOST_SERIALIZATION_NVP(dr);
    std::cout <<"year:"<<dr->year << "month:"<< dr->month <<"day:"<<dr->day<<std::endl;
}

其使用方式基本上跟序列化其他的基礎類型差不多,使用超級方便,測試結果:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<dat class_id="0" tracking_level="1" version="0" object_id="_0">
    <data.year>2014</data.year>
    <data.month>2</data.month>
    <data.day>10</data.day>
</dat>
</boost_serialization>

在轉儲指針時,我們需要注意一點就是當轉儲的指針有多個時,並且這些指針所指的地址一致時,這時候,轉儲文件會是怎樣的呢,先來看看代碼:

void save_MulPointer()
{
.    std::ofstream file("Object4.xml");
    boost::archive::xml_oarchive oa(file);
    date* dat = new date(2014,2,10);
    date* tmp = dat;

    date d(2014,2,11);
    date& ref = d;
    oa & BOOST_SERIALIZATION_NVP(dat);
    oa & BOOST_SERIALIZATION_NVP(tmp);

    oa & BOOST_SERIALIZATION_NVP(d);
    oa & BOOST_SERIALIZATION_NVP(ref);

}

void load_MulPointer()
{
    std::ifstream file("Object4.xml");
    boost::archive::xml_iarchive ia(file);
    date* dr,*tm;
    ia & BOOST_SERIALIZATION_NVP(dr);
    ia & BOOST_SERIALIZATION_NVP(tm);
    std::cout<<"year:"<<dr->year<<"month:"<<dr->month<<"day:"<<dr->day<<std::endl;
    std::cout<<"year:"<<tm->year<<"month:"<<tm->month<<"day:"<<tm->day<<std::endl;
}

在這個案例中,分別針對指針和引用進行序列化,測試結果如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<dat class_id="0" tracking_level="1" version="0" object_id="_0">
    <data.year>2014</data.year>
    <data.month>2</data.month>
    <data.day>10</data.day>
</dat>
<tmp class_id_reference="0" object_id_reference="_0"></tmp>
<d object_id="_1">
    <data.year>2014</data.year>
    <data.month>2</data.month>
    <data.day>11</data.day>
</d>
<ref object_id_reference="_1"></ref>
</boost_serialization>

從測試結果可以看出,針對指針和引用的序列化其實都是隻有一個對象,並通過使用引用計數的方式來實現對象的共享。

4. 將serialize操作分爲save和load操作

    在這種操作中主要是將我們的serialize函數實現拆分爲兩個子函數來實現,因爲在前面的案例中,我們的序列化操作都是實現serialize函數,現在我們需要實現save和load函數,這樣的好處就是能夠將原有的序列化機制進行細分,這樣有利於後續相關功能的擴展,代碼如下:

struct date
{
    date()
    {
        year = month = day = 0;
    }
    date(int year,int month,int day)
    {
        this->year = year;
        this->month = month;
        this->day = day;
    }

/*    template<class Archive>
    void serialize(Archive& archive,const unsigned int version)
    {
        //archive & year;
        //archive & month;
        //archive & day;
        archive & BOOST_SERIALIZATION_NVP(year);
        archive & BOOST_SERIALIZATION_NVP(month);
        archive & BOOST_SERIALIZATION_NVP(day);
    }
    */
    template<class Archive>
    void save(Archive& archive,const unsigned int version) const
    {
        archive & BOOST_SERIALIZATION_NVP(year);
        archive & BOOST_SERIALIZATION_NVP(month);
        archive & BOOST_SERIALIZATION_NVP(day);
    }

    template<class Archive>
    void load(Archive& archive,const unsigned int version)
    {
        archive & BOOST_SERIALIZATION_NVP(year);
        archive & BOOST_SERIALIZATION_NVP(month);
        archive & BOOST_SERIALIZATION_NVP(day);
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
    int year;
    int month;
    int day;
};

在date類中,我們需要實現save函數和load函數,並且save函數需要實現爲const函數的形式,在定義函數的末尾我們需要添加BOOST_SERIALIZATION_SPLIT_MEMBER這個宏,測試結果如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="11">
<dat class_id="0" tracking_level="1" version="0" object_id="_0">
    <year>2014</year>
    <month>2</month>
    <day>10</day>
</dat>
</boost_serialization>
發佈了52 篇原創文章 · 獲贊 10 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章