定義
- 程序員在編寫應用程序的時候往往需要將程序的某些數據存儲在內存中,然后將其寫入某個文件或是將它傳輸到網絡中的另一臺計算機上以實現通訊。這些過程將會涉及到程序數據轉化成能被存儲并傳輸的格式,因此被稱為“序列化”(Serialization),而它的逆過程則可被稱為“反序列化” (Deserialization)
- 簡單來說,序列化就是將對象實例的狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它根據流重構對象。這兩個過程結合起來,可以輕松地存儲和傳輸數據。例如,可以序列化一個對象,然后使用 HTTP 通過 Internet 在客戶端和服務器之間傳輸該對象。
總結
- 序列化:將對象變成字節流的形式傳出去。
- 反序列化:從字節流恢復成原來的對象。
序列化的好處
- 將對象存儲于硬盤上 ?,便于以后反序列化使用
- 在網絡上傳送對象的字節序列時便捷性、靈活性
C++對象序列化的四種方法
JSON文本序列化方式
- 使用jsoncpp或cJSON等庫,將內存中的數據結構序列化為JSON格式的文本串。
Google Protocol Buffers(protobuf)(推薦)
目的
- Google Protocol Buffers (GPB)是Google內部使用的數據編碼方式,旨在用來代替XML進行數據交換。可用于數據序列化與反序列化。主要特性有:高效;語言中立;可擴展
- 官方文檔
- github地址
- 參考示例
Boost.Serialization(推薦)
目的
- Boost.Serialization可以創建或重建程序中的等效結構,并保存為二進制數據、文本數據、XML或者有用戶自定義的其他文件。該庫具有以下吸引人的特性: 代碼可移植(實現僅依賴于ANSI C++);深度指針保存與恢復;可以序列化STL容器和其他常用模版庫;數據可移植;非入侵性。
MFC Serialization (不推薦)
目的
- Windows平臺下可使用MFC中的序列化方法。MFC 對 CObject 類中的序列化提供內置支持。因此,所有從 CObject 派生的類都可利用 CObject 的序列化協議
.Net Framework (不推薦)
目的
- .NET的運行時環境用來支持用戶定義類型的流化的機制。它在此過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換為字節流,然后再把字節流寫入數據流。在隨后對對象進行反序列化時,將創建出與原對象完全相同的副本。
簡單總結
- 其中MFC和.Net框架的方法適用范圍很窄,只適用于Windows下,且.Net框架方法還需要.Net的運行環境
- 參考分析
- Google Protocol Buffers效率較高,但是數據對象必須預先定義,并使用protoc編譯,適合要求效率,允許自定義類型的內部場合使用。
- Boost.Serialization 使用靈活簡單,而且支持標準C++容器。
- 相比而言,MFC的效率較低,但是結合MSVS平臺使用最為方便。
- 為了考慮平臺的移植性、適用性和高效性,推薦大家使用Google的protobuf和Boost的序列化方案,下面介紹我使用這兩種方案的心得及注意事項。
進一步學習
Google Protocol Buffers
- Google Protocol Buffers protobuf相對而言效率應該是最高的,不管是安裝效率還是使用效率,protobuf都很高效,而且protobuf不僅用于C++序列化,還可用于Java和Python的序列化,使用范圍很廣。
protobuf支持的數據類型不是很豐富
- 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 | 可能包含任意順序的字節數據 |
protobuf不支持二維數組(指針),不支持STL容器序列化
- 這個缺陷挺大,因為稍復雜點的數據結構或類結構里出現二維數組、二維指針和STL容器(set、list、map等)很頻繁,但因為 protobuf簡單的實現機制,只支持一維數組和指針(用repeated修飾符修飾),不能使用repeated repeated來支持二維數組, 也不支持STL,因此在選擇該方案之前,一定 要確保你的數據結構里沒有這些不支持的類型。
protobuf嵌套后會改變類名稱
- protobuf支持類的嵌套,即在一個自定義類型中可以定義另一個自定義類型,但注意嵌套的自定義類型在經過protobuf處理后生成的類名稱并不是你定義的類名稱,而是加上了外層的類名稱作為前綴
Boost.Serialization
- Boost庫是個很龐大的庫,功能非常豐富,序列化只是其中的一個小分支,但為了使用Boost的序列化方案,你需要安裝整個Boost庫,所花費的磁盤空間和時間都很多,同樣支持的序列化功能也很強大,既支持二維數組(指針),也支持STL容器,更不需要我們用某種特殊的格式重新定義我們的類結構,其非侵入的性質使得我們無須改動已有的類結構即可序列化,這時非常贊的一個性質。
- 但是由于體積龐大,安裝復雜,如果只是簡單的序列化,沒必要使用該方案,只有protobuf不能滿足你的需求時,才應該考慮該方案。
- 安裝boost庫遇到的一系列問題 安裝boost庫本事就是一項很費時的工程,如果期間出現了各種錯誤,更加耗時耗耐心。
- 對于基本類型指針很難序列化
- 不能序列化變長數組
參考代碼
- C++ 序列化探索
- 1)對基本數據類型char,short,int,long,string的序列化;
- 2)支持序列化為socket流;
- 3)支持對std::vector、std::list、std::set、std::map的序列化;
參考鏈接
- 最常用的兩種C++序列化方案的使用心得(protobuf和boost serialization)
?