最常用的兩種C++序列化方案的使用心得(protobuf和boost serialization)

最常用的兩種C++序列化方案的使用心得(protobuf和boost serialization)

導(dǎo)讀

1.?什么是序列化?

2.?為什么要序列化?好處在哪里?

3.?C++對象序列化的四種方法

4.?最常用的兩種序列化方案使用心得

正文

1.?什么是序列化?

程序員在編寫應(yīng)用程序的時候往往需要將程序的某些數(shù)據(jù)存儲在內(nèi)存中,然后將其寫入某個文件或是將它傳輸?shù)骄W(wǎng)絡(luò)中的另一臺計算機(jī)上以實現(xiàn)通訊茴晋。這個將 程序數(shù)據(jù)轉(zhuǎn)化成能被存儲并傳輸?shù)母袷降倪^程被稱為“序列化”(Serialization),而它的逆過程則可被稱為“反序列化” (Deserialization)回窘。

簡單來說诺擅,序列化就是將對象實例的狀態(tài)轉(zhuǎn)換為可保持或傳輸?shù)母袷降倪^程。與序列化相對的是反序列化啡直,它根據(jù)流重構(gòu)對象烁涌。這兩個過程結(jié)合起來苍碟,可以輕 松地存儲和傳輸數(shù)據(jù)。例如撮执,可以序列化一個對象微峰,然后使用 HTTP 通過 Internet 在客戶端和服務(wù)器之間傳輸該對象。


總結(jié)

序列化:將對象變成字節(jié)流的形式傳出去抒钱。

反序列化:從字節(jié)流恢復(fù)成原來的對象蜓肆。

2.?為什么要序列化?好處在哪里谋币?

簡單來說仗扬,對象序列化通常用于兩個目的:?

(1) 將對象存儲于硬盤上? ,便于以后反序列化使用

(2)在網(wǎng)絡(luò)上傳送對象的字節(jié)序列

對象序列化的好處在哪里蕾额?網(wǎng)絡(luò)傳輸方面的便捷性早芭、靈活性就不說了,這里舉個我們經(jīng)匙绲可能發(fā)生的需求:你 有一個數(shù)據(jù)結(jié)構(gòu)退个,里面存儲的數(shù)據(jù)是經(jīng)過很多其它數(shù)據(jù)通過非常復(fù)雜的算法生成的,由于數(shù)據(jù)量很大调炬,算法又復(fù)雜语盈,因此生成該數(shù)據(jù)結(jié)構(gòu)所用數(shù)據(jù)的時間可能要很久 (也許幾個小時,甚至幾天)缰泡,生成該數(shù)據(jù)結(jié)構(gòu)后又要用作其它的計算刀荒,那么你在調(diào)試階段,每次運(yùn)行個程序匀谣,就光生成數(shù)據(jù)結(jié)構(gòu)就要花上這么長的時間照棋,無疑代價 是非常大的资溃。如果你確定生成數(shù)據(jù)結(jié)構(gòu)的算法不會變或不常變武翎,那么就可以通過序列化技術(shù)生成數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)存儲到磁盤上,下次重新運(yùn)行程序時只需要從磁盤上讀 取該對象數(shù)據(jù)即可溶锭,所花費(fèi)時間也就讀一個文件的時間宝恶,可想而知是多么的快,節(jié)省了我們的開發(fā)時間趴捅。

3.?C++對象序列化的四種方法

將C++對象進(jìn)行序列化的方法一般有四種垫毙,下面分別介紹:

3.1 Google Protocol Buffers(protobuf)

Google Protocol Buffers (GPB)是Google內(nèi)部使用的數(shù)據(jù)編碼方式,旨在用來代替XML進(jìn)行數(shù)據(jù)交換拱绑∽劢妫可用于數(shù)據(jù)序列化與反序列化。主要特性有:

高效

語言中立(Cpp, Java, Python)

可擴(kuò)展

官方文檔


3.2 Boost.Serialization

Boost.Serialization可以創(chuàng)建或重建程序中的等效結(jié)構(gòu)猎拨,并保存為二進(jìn)制數(shù)據(jù)膀藐、文本數(shù)據(jù)屠阻、XML或者有用戶自定義的其他文件。該庫具有以下吸引人的特性:

代碼可移植(實現(xiàn)僅依賴于ANSI C++)额各。

深度指針保存與恢復(fù)国觉。

可以序列化STL容器和其他常用模版庫。

數(shù)據(jù)可移植虾啦。

非入侵性麻诀。


3.3 MFC Serialization

Windows平臺下可使用MFC中的序列化方法。MFC 對 CObject 類中的序列化提供內(nèi)置支持傲醉。因此蝇闭,所有從 CObject 派生的類都可利用 CObject 的序列化協(xié)議。

MSDN中的介紹


3.4 .Net Framework

.NET的運(yùn)行時環(huán)境用來支持用戶定義類型的流化的機(jī)制需频。它在此過程中丁眼,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉(zhuǎn)換為字節(jié)流,然后再把字節(jié)流寫入數(shù)據(jù)流昭殉。在隨后對對象進(jìn)行反序列化時苞七,將創(chuàng)建出與原對象完全相同的副本。

3.5?簡單總結(jié)

這幾種序列化方案各有優(yōu)缺點挪丢,各有自己的適用場景蹂风。其中MFC和.Net框架的方法適用范圍很窄,只適用于Windows下乾蓬,且.Net框架方法還需要.Net的運(yùn)行環(huán)境惠啄。參考文獻(xiàn)1從序列化時間、反序列化時間和產(chǎn)生數(shù)據(jù)文件大小這幾個方面比較了前三種序列化方案任内,得出結(jié)論如下(僅供參考):

Google Protocol Buffers效率較高撵渡,但是數(shù)據(jù)對象必須預(yù)先定義,并使用protoc編譯死嗦,適合要求效率趋距,允許自定義類型的內(nèi)部場合使用。

Boost.Serialization 使用靈活簡單越除,而且支持標(biāo)準(zhǔn)C++容器节腐。

相比而言,MFC的效率較低摘盆,但是結(jié)合MSVS平臺使用最為方便翼雀。

為了考慮平臺的移植性、適用性和高效性孩擂,推薦大家使用Google的protobuf和Boost的序列化方案狼渊,下面介紹我使用這兩種方案的心得及注意事項。

4.?最常用的兩種序列化方案使用心得

關(guān)于這兩種方案的具體使用和示例沒什么好寫的类垦,因為優(yōu)秀的參考資料很多狈邑,請看后面給出的相關(guān)參考資料坦弟,這里只給出我使用時的一些心得,方便大家在選擇序列化方案時有個正確的參考官地,避免選擇錯誤酿傍,浪費(fèi)時間。

4.1 Google Protocol Buffers

protobuf相對而言效率應(yīng)該是最高的驱入,不管是安裝效率還是使用效率赤炒,protobuf都很高效,而且protobuf不僅用于C++序列化亏较,還可用于Java和Python的序列化莺褒,使用范圍很廣。但在使用過程中要注意兩個問題:

(1)protobuf支持的數(shù)據(jù)類型不是很豐富

protobuf屬于輕量級的雪情,因此不能支持太多的數(shù)據(jù)類型遵岩,下面是protobuf支持的基本類型列表,一般都能滿足需求巡通,不過在選擇方案之前尘执,還是先看看是否都能支持,以免前功盡棄宴凉。同樣該表也值得收藏誊锭,作為我們在定義類型時做參考。



(2)protobuf不支持二維數(shù)組(指針)弥锄,不支持STL容器序列化

這個缺陷挺大丧靡,因為稍復(fù)雜點的數(shù)據(jù)結(jié)構(gòu)或類結(jié)構(gòu)里出現(xiàn)二維數(shù)組、二維指針和STL容器(set籽暇、list温治、map等)很頻繁,但因為 protobuf簡單的實現(xiàn)機(jī)制戒悠,只支持一維數(shù)組和指針(用repeated修飾符修飾)熬荆,不能使用repeated?repeated來支持二維數(shù)組, 也不支持STL救崔,因此在選擇該方案之前惶看,一定?要確保你的數(shù)據(jù)結(jié)構(gòu)里沒有這些不支持的類型捏顺。

(3)protobuf嵌套后會改變類名稱

protobuf支持類的嵌套六孵,即在一個自定義類型中可以定義另一個自定義類型,但注意嵌套的自定義類型在經(jīng)過protobuf處理后生成的類名稱并不是你定義的類名稱幅骄,而是加上了外層的類名稱作為前綴劫窒,下面舉一個簡單的例子:

? ? message DFA {?

? ? ? ? required int32 _size =1;?


? ? ? ? message accept_pair {?

? ? ? ? ? required boolis_accept_state =1;?

? ? ? ? ? required boolis_strict_end =2;?

? ? ? ? ? optional stringapp_name =3;?

? ? ? ? }?


? ? ? ? repeated accept_pair accept_states =2;?

? ? }?


那么嵌套中的accept_pair 生成后的類不是accept_pair 而是DFA_accept_pair 。如果不想改類名稱拆座,將accept_pair 拿到外面與DFA平行定義即可主巍。

4.2 Boost.Serialization

Boost庫是個很龐大的庫冠息,功能非常豐富,序列化只是其中的一個小分支孕索,但為了使用Boost的序列化方案逛艰,你需要安裝整個Boost庫,所花費(fèi)的磁盤空間和時間都很多搞旭,同樣支持的序列化功能也很強(qiáng)大散怖,既支持二維數(shù)組(指針),也支持STL容器肄渗,更不需要我們用某種特殊的格式重新定義我們的類結(jié)構(gòu)镇眷,其非侵入的性質(zhì)使得我們無須改動已有的類結(jié)構(gòu)即可序列化,這時非常贊的一個性質(zhì)翎嫡。但是由于體積龐大欠动,安裝復(fù)雜,如果只是簡單的序列化惑申,沒必要使用該方案具伍,只有protobuf不能滿足你的需求時,才應(yīng)該考慮該方案圈驼。

(1)安裝boost庫遇到的一系列問題

安裝boost庫本事就是一項很費(fèi)時的工程沿猜,如果期間出現(xiàn)了各種錯誤,更加耗時耗耐心碗脊。我們可以從官網(wǎng)下載Boost庫的二進(jìn)制源碼進(jìn)行安裝啼肩,安裝方法可以參考網(wǎng)絡(luò)或后面我給出的參考資料。

安裝過程如下:

首先解壓安裝包衙伶,如果是tar.gz用tar zxvf解壓祈坠,如果是tar.bz2用tar jxvf解壓,解壓后進(jìn)入解壓后的目錄矢劲,依次運(yùn)行以下命令:

./bootstrap.sh

sudo ./b2 install

注:這里沒有指定安裝路徑赦拘,在第二個命令可以加入--prefix指定安裝目錄。


安裝時的注意事項:

注意1:要用root權(quán)限進(jìn)行安裝芬沉,否則會在安裝過程中報錯躺同,提示權(quán)限不足。

注意2:boost庫的安裝依賴一些環(huán)境丸逸,通常有Python蹋艺、bzip2和zlib,它們所在的軟件包分別為:

Ubuntu下:

zlib1g-dev

libbz2-dev

libpython2.7-dev (and libpython3.3-dev)


Fedora/Redhat下:

zlib-devel

libbz2-devel

python-devel (and python3-devel)

這也是安裝過程中報錯的主要來源黄刚。

報錯1:如果Python庫不完整捎谨,可能會報“?fatal error: pyconfig.h: No such file or directory compilation terminated.”或者“fatal error: patchlevel.h: No such file or directory”錯誤。解決方法如下:

Fedora系統(tǒng):sudo yum install python-devel

Ubuntu系統(tǒng):sudo apt-get? install python-dev

報錯2:報錯 “?libs/iostreams/src/bzip2.cpp:20:56: fatal error: bzlib.h: No such file or directory”,解決方案:

Fedora系統(tǒng):sudo yum install bzip2-devel

Ubuntu系統(tǒng)或Debian系統(tǒng):sudo apt-get install libbz2-dev

通常對于這些錯誤涛救,在Ubuntu系統(tǒng)下一般可以通過sudo apt-get install libboost-all-dev全部解決畏邢,但不一定行得通。

(2)安裝成功后检吆,如果未指定安裝位置舒萎,那么默認(rèn)將會安裝到/usr/local/lib和/usr/local/include下,那么我們在使用Boost庫進(jìn)行編譯時就需要使用-L和-I參數(shù)加上具體的lib和include路徑蹭沛,像下面這樣:

g++ -o test boost_test.cpp -I$BOOST_INCLUDE -L$BOOST_LIB -lboost_serialization

如果覺得每次都這樣很麻煩逆甜,那么可以將我們所要用到的lib和include文件加入到環(huán)境變量中,像下面這樣:

sudo cp /usr/local/lib/libboost_serialization.* /usr/lib

sudo cp -r /usr/local/include/boost /usr/include

然后在編譯時直接g++ -o test boost_test.cpp?-lboost_serialization即可致板。

注意:boost下面有兩個序列化lib文件:ibboost_serialization.lib?和 libboost_wserialization.lib交煞,那么這兩者有什么區(qū)別呢?

其實'w'?表示使用的是寬字符斟或,例如 wchar_t素征。

(3)boost不盡人意的地方

基本類型指針很難序列化,例如int *array萝挤,官網(wǎng)上是這么說的:

By default, data types designated primitive by?Implementation Levelclass serialization trait are never tracked. If it is desired totrack a shared primitive object through a pointer (e.g. along?used as a reference count), It should be wrappedin a class/struct so that it is an identifiable type.The alternative of changing the implementation level of alongwould affect alllongs serialized in the wholeprogram - probably not what one would intend.

也就是說如果你想序列化原生類型的指針御毅,需要給其加上struct或class使其變?yōu)轭愵愋驮傩蛄谢梢娪行┞闊┝洌@樣的需求往往也很頻繁端蛆,鑒于序列化機(jī)制的實現(xiàn)原理,boost庫暫時還不能很好的支持基本類型的指針序列化酥泛。

不能序列化變長數(shù)組(variable-sized array)今豆,會報錯說變長數(shù)組不是模板類類型。

(4)如果需要定義一個對象數(shù)組柔袁,如定義含有2個元素的class A對象數(shù)組呆躲,那么必須用A a[2]定義而不能用對象的指針A *a = new A[2]定義,這樣序列化a后默認(rèn)當(dāng)作一個A對象處理捶索,因此只能存儲一個對象的值插掂,后面的不會存儲。

(5)所謂boost很人性的非侵入性質(zhì)也有一定的條件:如果不想改動原來的類腥例,那么原來的類屬性必須是public的辅甥,這很容易解釋,因為你必須 要能在別處訪問到這些屬性并定義其序列化方式燎竖,當(dāng)然這也在其它地方暴露了類的結(jié)構(gòu)璃弄,具有一定的劣勢。這樣的條件往往很難滿足底瓣,因為我們定義的類屬性一般都 是private的谢揪,如果是這樣,且仍想要使用非侵入性質(zhì)捐凭,那么需要在類中添加以下聲明來開放訪問給 serialization 庫:

friend class boost::serialization::access;

這樣的方式比讓成員public更好拨扶。

文末也給大家,分享主要有C/C++茁肠,Linux患民,Nginx,ZeroMQ垦梆,MySQL匹颤,Redis,fastdfs托猩,MongoDB印蓖,ZK,流媒體京腥,CDN赦肃,P2P,K8S公浪,Docker他宛,TCP/IP,協(xié)程欠气,DPDK技術(shù)厅各,面試技巧方面的資料技術(shù)討論。

感興趣的朋友可以加群:812855908

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末预柒,一起剝皮案震驚了整個濱河市队塘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宜鸯,老刑警劉巖人灼,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異顾翼,居然都是意外死亡投放,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門适贸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灸芳,“玉大人,你說我怎么就攤上這事拜姿±友” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵蕊肥,是天一觀的道長谒获。 經(jīng)常有香客問我蛤肌,道長,這世上最難降的妖魔是什么批狱? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任裸准,我火速辦了婚禮,結(jié)果婚禮上赔硫,老公的妹妹穿的比我還像新娘炒俱。我一直安慰自己,他們只是感情好爪膊,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布权悟。 她就那樣靜靜地躺著,像睡著了一般推盛。 火紅的嫁衣襯著肌膚如雪峦阁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天耘成,我揣著相機(jī)與錄音拇派,去河邊找鬼。 笑死凿跳,一個胖子當(dāng)著我的面吹牛件豌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播控嗜,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼茧彤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了疆栏?” 一聲冷哼從身側(cè)響起曾掂,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎壁顶,沒想到半個月后珠洗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡若专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年许蓖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调衰。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡膊爪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚎莉,到底是詐尸還是另有隱情米酬,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布趋箩,位于F島的核電站赃额,受9級特大地震影響加派,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跳芳,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一芍锦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧筛严,春花似錦醉旦、人聲如沸饶米。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檬输。三九已至照瘾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丧慈,已是汗流浹背析命。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留逃默,地道東北人鹃愤。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像完域,于是被迫代替她去往敵國和親软吐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 序列化概述 當(dāng)兩個服務(wù)在進(jìn)行通信時吟税,彼此可以發(fā)送各種類型的數(shù)據(jù)凹耙。無論是何種類型的數(shù)據(jù),都會以字節(jié)序列的形式在網(wǎng)絡(luò)上...
    _張曉龍_閱讀 7,897評論 0 11
  • JAVA序列化機(jī)制的深入研究 對象序列化的最主要的用處就是在傳遞,和保存對象(object)的時候,保證對象的完整...
    時待吾閱讀 10,837評論 0 24
  • 前言 在做運(yùn)動員管理系統(tǒng)的時候肠仪,我用到C++中的對象遇到一個問題肖抱,就是保存對象的時候,想要將對象保存保存在文件中异旧,...
    YellowTag閱讀 4,847評論 0 1
  • 本文轉(zhuǎn)自劉明的分享意述。原文 簡介 什么是 Google Protocol Buffer? 假如您在網(wǎng)上搜索吮蛹,應(yīng)該會得...
    那樣風(fēng)采閱讀 1,577評論 0 1
  • 價值與尊嚴(yán)欲险,都在思考的問題,我們窮盡一生匹涮,到底該怎樣活天试,才能有價值,活得有尊嚴(yán)然低?在如今這個物欲橫流的時代喜每,住豪宅...
    流浪的喵記閱讀 591評論 2 5