用了都说好:D
Serialization Tutorial
畅游C++ Boost Serialization 序列化
C++ Boost 序列化
使用Boost的Serialization库序列化STL标准容器
ArchiveTest.cpp
#include
#include
#include
#include
#include
#include
#include
class A
{
private:
// 为了能让串行化类库能够访问私有成员,所以要声明一个友元类
friend class boost::serialization::access;
int a;
double b;
// 串行化的函数,这一个函数完成对象的保存与恢复
// 要实现保存与加载,这个函数的实现是重点!!
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// 如果类Archive 是一个输出存档,则操作符& 被定义为<<.
// 如果类Archive 是一个输入存档,则操作符& 被定义为>>.
ar & a;
ar & b;
}
public:
A(int aa,double bb):a(aa),b(bb){}
A(){}
void print(){std::cout<<a<<' '<<b<<std::endl;}
};
void TxtArchiveTest()
{
std::ofstream fout("file.txt");// 把对象写到file.txt文件中
boost::archive::text_oarchive oa(fout); // 文本的输出归档类,使用一个ostream来构造
A obj(1,2.5);
oa<<obj; // 保存obj对象
fout.close();// 关闭文件
std::ifstream fin("file.txt");
boost::archive::text_iarchive ia(fin); // 文本的输入归档类
A newobj;
ia>>newobj; // 恢复到newobj对象
newobj.print();
fin.close();
}
void BinArchiveTest()
{
std::ofstream fout("file.bin");// 把对象写到file.txt文件中
boost::archive::binary_oarchive oa(fout); // 文本的输出归档类,使用一个ostream来构造
A obj(1,2.5);
oa<<obj; // 保存obj对象
fout.close();// 关闭文件
std::ifstream fin("file.bin");
boost::archive::binary_iarchive ia(fin); // 文本的输入归档类
A newobj;
ia>>newobj; // 恢复到newobj对象
newobj.print();
fin.close();
}
int main()
{
std::cout<<"TxtArchiveTest:\n";
TxtArchiveTest();
std::cout<<std::endl;
std::cout<<"BinArchiveTest\n";
BinArchiveTest();
std::cout<<std::endl;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.0)
project(archive)
SET(CMAKE_BUILD_TYPE "Release")
# SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
# SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# add_compile_options(-g)
find_package(Boost REQUIRED COMPONENTS
regex
graph
chrono
thread
system
filesystem
serialization)
if (Boost_FOUND)
message(STATUS "find Boost:\"${Boost_INCLUDE_DIRS}\"")
message(STATUS "find Boost:\"${Boost_LIBRARIES}\"")
include_directories(${Boost_INCLUDE_DIRS})
add_definitions(-DENABLE_BOOST)
list(APPEND LINK_LIB_LIST ${Boost_LIBRARIES})
endif (Boost_FOUND)
include_directories(
${PROJECT_SOURCE_DIR}
${Boost_INCLUDE_DIRS}
)
add_executable(archive
ArchiveTest.cpp
)
target_link_libraries(archive
${Boost_LIBRARIES}
)
序列化一个标准类型,需要使用boost自带的头文件,在Serialization中,比如要序列化一个STL容器,要使用boost自带的头文件,不能直接#include 。类似的头文件还有vector.hpp string.hpp set.hpp map.hpp slist.hpp等等。
//STL容器
#include // Serialization中特定的头文件,在list.hpp中已经包含了stl的list头文件
Class A
{
...
list<int> list;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & list;
}
...
}
//数组和指针
//对于数组和指针可以直接序列化
Class A
{
...
int a[10];
int *b
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & a;
ar & b;
}
...
}
如果是自己定义的类别该怎么办呢?在最简单的状况下,只需要撰写一个名为serialize()的成员函数。
侵入式序列化:
class CURL
{
public:
std::string sHost;
unsigned int sPort;
std::string sPath;
public:
template<class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar& sHost;
ar& sPort;
ar& sPath;
}
};
非侵入式序列化
class CURL
{
public:
std::string sHost;
unsigned int sPort;
std::string sPath;
};
// 改写成在 boost::serialization 这个 namespace 下的全域函数
namespace boost {
namespace serialization {
template<class Archive>
void serialize(Archive& ar, CURL& rURL, const unsigned int version)
{
// 如果类Archive 是一个输出存档,则操作符& 被定义为<<.
// 如果类Archive 是一个输入存档,则操作符& 被定义为>>.
ar& rURL.sHost;
ar& rURL.sPort;
ar& rURL.sPath;
}
}
}
另外,他还有一个参数是 version,这是用来纪录数据版本用的;可以根据不同的版本、进行跨版本的存储控制。不过这部分算是比较进阶的东西,暂时用不上。
将储存和读取分开处理。根据 Boost serialization 的设计下,主要是透过 serialize() 这样的单一函式,来解决输入、输出的功能,并避免可能的两个方向不一致的可能性。但是,有的时候,我们可能还是会需要输入、输出两边是不一样的状况。
例如,有的函式库的类别其实会把成员资料都设定成 private 或 proteced、仅能透过成员函式做存取,以保护资料。
比如说,可能会像下面的样子:
class CURL
{
protected:
std::string sHost;
unsigned int sPort;
std::string sPath;
public:
std::string getHost() const { return sHost; }
std::string getPath() const { return sPath; }
unsigned int getPort() const { return sPort; }
void setHost(const std::string& val) { sHost = val; }
void setPath(const std::string& val) { sPath = val; }
void setPort(const unsigned int& val) { sPort = val; }
};
这个时候,除非要去直接修改 CURL 这个类别,基本上就没办法靠单一的 serialize() 来同时处理输出和输入。如果遇到这样的情况,Boost serialization 也提供了把 serialize() 拆分成 save() / load() 两个函式的功能,让开发者可以使用。比如说,这边就可以写成:
namespace boost {
namespace serialization {
template<class Archive>
void save(Archive& ar, const CURL& t, unsigned int version)
{
ar& t.getHost();
ar& t.getPort();
ar& t.getPath();
}
template<class Archive>
void load(Archive& ar, CURL& t, unsigned int version)
{
std::string sVal;
unsigned int iVal;
ar& sVal; t.setHost(sVal);
ar& iVal; t.setPort(iVal);
ar& sVal; t.setPath(sVal);
}
}
}
BOOST_SERIALIZATION_SPLIT_FREE(CURL);这边的作法,基本上就是和撰写 serialize() 的方法依样,不过这边把程式分成 save() / load() 两个版本。
最后,则是要再通过 BOOST_SERIALIZATION_SPLIT_FREE() 这个巨集(定义在
而如果是成员函式的 serialize() 要拆分的话,则是要使用 BOOST_SERIALIZATION_SPLIT_MEMBER() 这个巨集(定义在