序列化能够把对象转化成一个字节流存储或者传输,在须要时再回复成与原始状态一致的等价对象。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; } }