閒來無事發現了一個基於C++實現的序列化工具,相比於其餘(好比Boost serialization或Google protobuf,恰巧都用過,之後再介紹),使用簡單,感受不錯,下面作個摸索。html
cereal介紹ios
cereal是一個開源的(BSD License)、輕量級的、支持C++11特性的、僅僅包含頭文件實現的、跨平臺的C++序列化庫。它能夠將任意的數據類型序列化成不一樣的表現形式,好比二進制、XML格式或JSON。cereal的設計目標是快速、輕量級、易擴展——它沒有外部的依賴關係,並且能夠很容易的和其餘代碼封裝在一塊或者單獨使用。c++
cereal支持標準庫的幾乎每個類型的序列化。cereal也徹底支持繼承和多態。因爲cereal被設計爲一個精簡、快速的庫,它不像其餘序列化庫(好比Boost)在同一層次上會進行對象跟蹤,這也致使了它不支持原始指針(raw pointer)和引用,可是智能指針(好比std::shared_ptr和std::unique_ptr)是沒有問題的。git
cereal適用於基於C++11標準的各類編譯器
cereal使用了一些C++11的新特性,所以須要一個兼容性更好的的C++編譯器才能正常工做。已被驗證可用的編譯器有g++4.7.三、clang++3.三、MSVC2013,或者更新版本。
它也可能能夠在老版本編譯器上工做,但並不保證徹底支持。當使用g++或clang++編譯器時,cereal同時須要libstdc++和libc++庫。
cereal:更快速,更好的壓縮
在簡單的性能測試中,cereal一般比Boost的序列化庫速度更快,並且產生的二進制形式佔用更少的空間,尤爲是針對更小的對象。cereal使用了C++中的速度最快的XML和JSON解析器和包裝器。
cereal是可擴展的
cereal提供了對標準庫的序列化支持,好比二進制的,XML和JSON序列化器。
cereal的源代碼相比Boost來說,更容易理解和擴展。 若是你須要別的東西,cereal能夠很容易地擴展,好比添加自定義序列化存檔或類型。github
cereal是易於使用的
在代碼增長cereal序列化功能能夠簡化爲包含一個頭文件,寫一個序列化函數。不管是從概念上仍是代碼層次上,cereal的功能都是自文檔化的。
若是你使用錯誤,cereal儘量的在編譯期觸發靜態斷言。json
對於Boost使用者來講,cereal提供了類似的語法,若是你使用過Boost的序列化庫,你會發現cereal的語法看起來很熟悉。api
若是你是從Boost轉向使用cereal,必定要閱讀這個過渡指南:http://uscilab.github.io/cereal/transition_from_boost.html函數
簡單的使用 工具
好吧,廢話就這麼多,先上一個簡單的事例:性能
std::ofstream os("my.xml"); cereal::XMLOutputArchive archive(os); int age = 26; std::string name = "lizheng"; archive(CEREAL_NVP(age), cereal::make_nvp("Name", name));
以上代碼完成了對一個int類型和string類型的xml序列化實現。結果以下:
<?xml version="1.0" encoding="utf-8"?> <cereal> <age>26</age> <Name>lizheng</Name> </cereal>
注意上面代碼中的cereal::XMLOutputArchive,其實還有針對JSON、二進制序列化的類,若是是序列化爲JSON串,結果以下(代碼在最下面):
{
"age": 26,
"Name": "lizheng"
}
個人Demo
完整代碼以下(或點此下載完整工程,或者從個人github下載包括cereal頭文件在內的整個項目):
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include "cereal/archives/binary.hpp" 5 #include "cereal/archives/xml.hpp" 6 #include "cereal/archives/json.hpp" 7 #include "cereal/types/unordered_map.hpp" 8 #include "cereal/types/memory.hpp" 9 #include "cereal/types/string.hpp" //必定要包含此文件,不然沒法將std::string序列化爲二進制形式,請看:https://github.com/USCiLab/cereal/issues/58 10 11 using namespace std; 12 13 struct MyRecord 14 { 15 int x, y; 16 float z; 17 18 template <class Archive> 19 void serialize(Archive & ar) 20 { 21 ar(x, y, z); 22 } 23 24 friend std::ostream& operator<<(std::ostream& os, const MyRecord& mr); 25 }; 26 27 std::ostream& operator<<(std::ostream& os, const MyRecord& mr) 28 { 29 os << "MyRecord(" << mr.x << ", " << mr.y << "," << mr.z << ")\n"; 30 return os; 31 } 32 33 struct SomeData 34 { 35 int32_t id; 36 std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data; 37 38 SomeData(int32_t id_=0) : id(id_), data(new std::unordered_map<uint32_t, MyRecord>) 39 { 40 41 } 42 43 template <class Archive> 44 void save(Archive & ar) const 45 { 46 ar(id, data); 47 } 48 49 template <class Archive> 50 void load(Archive & ar) 51 { 52 ar(id, data); 53 } 54 55 void push(uint32_t, const MyRecord& mr) 56 { 57 data->insert(std::make_pair(100, mr)); 58 } 59 60 void print() 61 { 62 std::cout << "ID : " << id << "\n"; 63 if (data->empty()) 64 return; 65 for (auto& item : *data) 66 { 67 std::cout << item.first << "\t" << item.second << "\n"; 68 } 69 } 70 }; 71 72 void Serialization_XML() 73 { 74 { 75 std::ofstream os("my.xml"); 76 77 cereal::XMLOutputArchive archive(os); 78 79 int age = 26; 80 std::string name = "lizheng"; 81 82 //#define CEREAL_NVP(T) ::cereal::make_nvp(#T, T) 83 archive(CEREAL_NVP(age), cereal::make_nvp("Name", name)); 84 85 //os.close(); //注意:這裏不能顯示關閉ofstream,不然序列化沒法寫入到文件 86 } 87 88 { 89 std::ifstream is("my.xml"); 90 cereal::XMLInputArchive archive(is); 91 92 int age; 93 std::string name; 94 95 archive(age, name); 96 std::cout << "Age: " << age << "\n" << "Name: " << name << "\n"; 97 } 98 } 99 100 void Serialization_JSON() 101 { 102 { 103 std::ofstream os("my.json"); 104 cereal::JSONOutputArchive archive(os); 105 106 int age = 26; 107 std::string name = "lizheng"; 108 109 archive(CEREAL_NVP(age), cereal::make_nvp("Name", name)); 110 } 111 112 { 113 std::ifstream is("my.json"); 114 cereal::JSONInputArchive archive(is); 115 116 int age; 117 std::string name; 118 119 archive(age, name); 120 std::cout << "Age: " << age << "\n" << "Name: " << name << "\n"; 121 } 122 } 123 124 125 void Serialization_Binary() 126 { 127 { 128 std::ofstream os("my.binary", std::ios::binary); 129 cereal::BinaryOutputArchive archive(os); 130 131 int age = 26; 132 std::string name = "lizheng"; 133 134 archive(CEREAL_NVP(age), CEREAL_NVP(name)); 135 } 136 { 137 std::ifstream is("my.binary", std::ios::binary); 138 cereal::BinaryInputArchive archive(is); 139 140 int age; 141 std::string name; 142 143 archive(age, name); 144 std::cout << "Age: " << age << "\n" << "Name: " << name << "\n"; 145 } 146 } 147 148 void Serialization_Obj() 149 { 150 { 151 std::ofstream os("obj.cereal", std::ios::binary); 152 cereal::BinaryOutputArchive archive(os); 153 154 MyRecord mr = { 1, 2, 3.0 }; 155 156 SomeData myData(1111); 157 myData.push(100, mr); 158 159 archive(myData); 160 } 161 { 162 std::ifstream is("obj.cereal", std::ios::binary); 163 cereal::BinaryInputArchive archive(is); 164 165 SomeData myData; 166 archive(myData); 167 myData.print(); 168 } 169 } 170 171 172 int main() 173 { 174 Serialization_XML(); std::cout << "----------------------\n"; 175 176 Serialization_JSON(); std::cout << "----------------------\n"; 177 178 Serialization_Binary(); std::cout << "----------------------\n"; 179 180 Serialization_Obj(); std::cout << "----------------------\n"; 181 182 getchar(); 183 return 0; 184 }