序列化能夠把對象轉化成一個字節流存儲或者傳輸,在須要時再回覆成與原始狀態一致的等價對象。C++標準沒有定義這個功能。boost.serialization以庫的形式提供了這個功能,很是強大,能夠序列化C++中各類類型,並且簡單易用。html
boost.serialization庫必須編譯後才能使用。有關boost庫的編譯能夠參考以前的文章windows下編譯和安裝boost庫.ios
serialization庫把存檔和類型的序列化徹底分離開來,任意的數據類型均可以採用任意格式的存檔保存。因此頭文件被分別放在了兩個目錄下:
<boost/archive/>
目錄的頭文件處理序列化的存檔表現形式
<boost/serialization>
目錄裏的頭文件提供對各類數據類型的序列化能力。windows
boost.serialization庫位於名稱空間boost.archive
,在使用時必須根據須要包含特定的存檔頭文件和序列化頭文件。
例如:數組
#include <boost/archive/text_oarchive.hpp> //文本格式輸入存檔 #include <boost/archive/text_iarchive.hpp> //文本格式輸出存檔 #include <boost/serialization/vector.hpp> //vector的序列化實現頭文件 using namespace boost:archive;//打開名稱空間
serialization庫的三個基本概念:函數
存檔在serialization庫中表現爲一系列的字節(不必定是ASCII或者二進制),它對應任意的C++對象,能夠持久化保存並在某個時刻恢復成C++對象。測試
根據存檔格式分爲:spa
純文本格式 text_iarchive
text_oarchive
指針
xml格式 xml_iarchive
xml_oarchive
rest
二進制格式 binary_iarchive
binary_oarchive
code
根據輸入輸出存檔方向:
輸出存檔(saving) : 把C++對象序列化爲某種格式的字節流
輸入存檔(loading) : 把某種格式的字節流反序列化爲等價的C++對象。
只有可序列化的C++類型纔可以被序列化爲字節流,保存到存檔中或這從存檔中恢復。
(1) C++基本類型都是可序列化的,如bool、int、double、enum。
(2) 字符串string、wstring是可序列化的
(3) 自定義類型若是有特定形式的成員函數或者自由函數serialize()也是可序列化的。
(4) 可序列化類型的數組也是可序列化的。
(5) 可序列化類型的指針和引用也是可序列化的。
注:serialization庫支持標準庫裏定義的complex
bitset
valarray
pair
等
對標準容器支持,包括vector、deque、list、set、map,不支持stack,queue,priority_queue.
序列化和反序列化是兩個互逆的過程。
序列化操做符: operator<<
operator&
反序列化操做符: operator>>
operator&
//序列化 ofstream ofs("serial.txt"); //輸出文件流 string str("boost serializaiton"); { boost::archive::text_oarchive oa(ofs);//文本輸出存檔鏈接到文件流 oa & str; //序列化到輸出存檔 } //反序列化 ifstream ifs("serial.txt");//文件輸入流 string istr; { boost::archive::text_iarchive ia(ifs); //文本輸入存檔鏈接到文件流 ia & istr;//從輸入文檔反序列化 } assert(istr == str);
輸出存檔(如:text_oarchive
)的構造函數須要使用一個輸出流,建立輸出存檔後,就可使用operator<<
或operator&
向存檔寫入對象。
輸如存檔(如:text_iarchive
)構造時要求使用一個輸入流,使用operator<<
和operator&
執行反序列化。
一個簡單的序列化操做模版類:
//BoostArchive.h #ifndef _BOOST_ARCHIVE_H_ #define _BOOST_ARCHIVE_H_ #include <list> #include <fstream> #include <string> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> using std::list; using std::ifstream; using std::ofstream; using std::string; template <class T> class BoostArchive { public: typedef T entity_type; typedef boost::archive::text_iarchive InputArchive; typedef boost::archive::text_oarchive OutputArchive; BoostArchive(const string & archive_file_path) : _file_path_name(archive_file_path) , _p_ofs(NULL) , _p_output_archive(NULL) , _entity_nums(0) { load_arvhive_info(); } ~BoostArchive() { close_output(); } //存儲一個對象,序列化 void store(const entity_type & entity); //反序列化, 提取全部對象 bool restore(list<entity_type> & entitys); size_t size() const { return _entity_nums; } private: void save_archive_info() //保存已序列化的對象個數信息 { ofstream ofs; ofs.open(get_archive_info_file_path(),std::ios::out | std::ios::trunc); if (ofs.is_open()) { ofs << _entity_nums; } ofs.close(); } void load_arvhive_info()//讀取已序列化的對象個數信息 { ifstream ifs; ifs.open(get_archive_info_file_path(),std::ios_base::in); if (ifs.is_open() && !ifs.eof()) { int enity_num = 0; ifs >> enity_num; _entity_nums = enity_num; } ifs.close(); } string get_archive_info_file_path() { return "boost_archive_info.meta"; } void close_output() { if (NULL != _p_output_archive) { delete _p_output_archive; _p_output_archive = NULL; save_archive_info(); } if (NULL != _p_ofs) { delete _p_ofs; _p_ofs = NULL; } } private: size_t _entity_nums; string _file_path_name; ofstream * _p_ofs; OutputArchive * _p_output_archive; }; template <class T> bool BoostArchive<T>::restore( list<entity_type> & entitys ) { close_output(); load_arvhive_info(); ifstream ifs(_file_path_name); if (ifs) { InputArchive ia(ifs); for (size_t cnt = 0; cnt < _entity_nums; ++cnt) { entity_type entity; ia & entity; entitys.push_back(entity); } return true; } return false; } template <class T> void BoostArchive<T>::store( const entity_type & entity ) { if (NULL == _p_output_archive) { _p_ofs = new ofstream(_file_path_name); _p_output_archive = new OutputArchive(*_p_ofs); } (*_p_output_archive) & entity; ++_entity_nums; } #endif
自定義類型可使用兩種方式實現可序列化:侵入式和非侵入式
侵入式可序列化
侵入式方式要求類必須實現以下形式的一個成員函數serialize():
template<typename Archive> void serialize(Archive & ar, const unsigned int version) { ... }
第一個參數是被用於序列化或反序列化的存檔,第二個參數是一個整型的版本號。在serialize函數內部,應當使用operator&
存取類的全部必要的數據成員。
boost::serialization::access
是一個輔助類,聲明瞭一系列的靜態成員函數間接調用自定義類的serialize(),存檔經過它來完成對自定義類的序列化。通常在自定義類中聲明boost::serialization::access
爲友元來授予訪問權限,serialize()
設置爲private。
侵入式序列化示例:
//自定義類型的序列化 //侵入式 class Student { public: Student() : _id(-1) , _name("") {} Student(const int id, const string & name) : _id(id) , _name(name) {} void add_score(double score) { _scores.push_back(score); } double get_avg_score() const { return (_scores.size() == 0) ? 0 : (std::accumulate(_scores.begin(),_scores.end(),0) / _scores.size()); } string get_student_msg() const { stringstream ss; ss << "\nID: " << _id << " NAME: " << _name << "\n"; for (auto iter = _scores.begin(); iter != _scores.end(); ++iter) { ss << *iter << " "; } ss << "\nAVG_SCORE: " << get_avg_score(); return ss.str(); } private: friend boost::serialization::access; //聲明友元,授予訪問權限 template<typename Archive> void serialize(Archive & ar, const unsigned int version) //序列化函數 { ar & _id; ar & _name; ar & _scores; } private: string _name; int _id; vector<double> _scores; };
測試代碼(使用到了上面的輔助類BoostArchive):
void TestArchive() { Student s1(1,"cm"); s1.add_score(100); s1.add_score(80); s1.add_score(90); Student s2(2,"cj"); s2.add_score(100); s2.add_score(90); s2.add_score(90); Student s3(3,"zj"); s3.add_score(100); s3.add_score(60); s3.add_score(90); string archive_file_name("students.dat"); BoostArchive<Student> archive(archive_file_name); archive.store(s1); //序列化 archive.store(s2); archive.store(s3); list<Student> list1; archive.restore(list1); //反序列化,恢復數據 for (auto iter = list1.cbegin(); iter != list1.end(); ++iter) { cout << iter->get_student_msg(); } }
非侵入式可序列化
侵入式可序列化的缺點是要修改類定義,添加一些代碼。若是某個類定義是沒法修改的,就只能使用非侵入的方式,定義一個以下形式的自由函數:
//非侵入式 namespace boost{ namespace serialization{ template<typename Archive> void serialize(Archive & ar, some_class & t, const unsigned int version) { ... } } }
自由函數serialize()與成員函數serialize相似,多了一個自定義類型的參數t,在函數體內用它來完成序列化和反序列化。由於非侵入式不能訪問類的私有成員,因此要求要被序列化的成員爲public。
其次爲了方便編譯器查找自由函數serialize,一般應該定義在名稱空間boost::serialization
,或boost::archive
和自定義類型所在的名稱空間。
非侵入式序列化示例:
struct Person { Person() :_id(-1) , _name("") { } Person(int id, const string & name) :_id(id) , _name(name) { } string get_msg() const { stringstream ss; ss << _id << " " << _name; return ss.str(); } int _id; string _name; }; //非侵入式 namespace boost{ namespace serialization{ template<typename Archive> void serialize(Archive & ar, Person & p, const unsigned int version) { ar & p._id; ar & p._name; } }