C++Boost的序列化

34 篇文章 0 订阅

序列化概述

什么是序列化

程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化”(Deserialization)。
  简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻松地存储和传输数据。例如,可以序列化一个对象,然后使用HTTP通过Internet在客户端和服务器之间传输该对象。

序列化包含侵入式序列化、非侵入式序列化、STL序列化
在这里插入图片描述序列化:将对象变成字节流的形式传出去。
反序列化:从字节流恢复成原来的对象。

为什么要用序列化

1、将对象存储于硬盘上,便于以后反序列化使用
2、在网络上传送对象的字节序列
  对网络传输而言,显而易见,序列化对象带来了便捷性和灵活性。另一方面,序列化也节省了开发时间。比如:有一个数据结构存储了大量数据,而里面存储的数据又是经过很多其它数据通过非常复杂的算法长时间计算生成的,因此生成该数据结构所用数据的时间要很久。生成该数据结构后又要用作其它的计算。那么在调试阶段,每次运行程序,都需要花费大量时间生成这个数据,无疑代价是非常大的。如果生成数据结构的算法不会变或不常变,那么就可以通过序列化技术生成数据结构数据存储到磁盘上,下次重新运行程序时只需要从磁盘上读取该对象数据即可,而不需要重新计算、生成这些数据,这样大大节省了我们的开发时间。

Boost.Serialization

Boost.Serialization可以创建或重建程序中的等效结构,并保存为二进制数据、文本数据、XML或者有用户自定义的其他文件。该库具有以下吸引人的特性:

  • 代码可移植(实现仅依赖于ANSI C++)。
  • 深度指针保存与恢复。
  • 可以序列化STL容器和其他常用模版库。
  • 数据可移植。
  • 非入侵性。

侵入式序列化

侵入式序列化时,需要在class里面加入序列化的代码

  1. 先引用 boost 头文件
  2. 在类的声明中, 编写序列化函数,该函数的格式如下:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
//version是版本号,可用于版本控制
{
	ar& m_str;
}

  1. 类的实例化和赋值
  2. 定义一个序列化的对象和数据流的写入
boost::archive::text_oarchive text_oa(text_sstream);//文本方式
boost::archive::binary_oarchive binary_oa(binary_sstream);//二进制方式
binary_oa << info;//将对象info的序列化数据以二进制存储形式写入内存

#include <boost/archive/text_oarchive.hpp> 
#include <boost/archive/text_iarchive.hpp> 
#include <fstream> 
class Student
{
	friend class boost::serialization::access;

public:
	Student(){}
	~Student(){}
	Student(int a,float b):id_(a), score_(b){}
	inline int id() { return id_; }
	inline float score() { return score_; }

private:
	template<typename T>
	void serialize(T& arch, const unsigned int version) {
		arch& id_;
		arch& score_;
	}
	int id_;
	float score_;
};

#include<iostream>
#include"student.h"
using namespace std;


int main() {

	std::ofstream out("archiv.txt");
	boost::archive::text_oarchive oa(out);
	Student stu(1, 2.3);
	oa << stu;
	out.close();
	cout << "序列化完毕!" << endl;

	std::ifstream in("archiv.txt");
	boost::archive::text_iarchive ia(in);
	ia >> stu;
	cout << stu.id() << "--" << stu.score() << endl;
	in.close();

	system("pause");
	return 0;
}

非侵入式序列化

如果class是早已存在的,且我们不想再改变class里面的代码时,这个时候,我们可以使用非侵入式的序列化。非侵入式序列化时,序列化函数需要访问数据成员,这就要求将class的数据成员暴露出来,即public,而不是private。其序列化的步骤和上面的侵入式序列化步骤一致。

Boost.Serialization的使用

txt文本格式序列化实例

  • 使用<<和>>运算符完成序列化和反序列化
  • 使用&运算符完成序列化和反序列化

XML格式序列化实例

步骤上与txt文本不同的地方在于,需要将数据打包到一个名为 BOOST_SERIALIZATION_NVP 的宏中。

#include <boost/archive/xml_iarchive.hpp> 
#include <boost/archive/xml_oarchive.hpp> 
#include <iostream> 
#include <fstream> 
 
void save() 
{ 
	std::ofstream file("archive.xml"); 
	boost::archive::xml_oarchive oa(file); 
	std::string s = "Hello World!\n"; 
	oa & BOOST_SERIALIZATION_NVP(s); 
} 
 
void load() 
{ 
	std::ifstream file("archive.xml"); 
	boost::archive::xml_iarchive ia(file); 
	std::string s;
	ia & BOOST_SERIALIZATION_NVP(s); 
	std::cout << s << std::endl; 
}

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<s>Hello World!</s>
</boost_serialization>

数组的序列化

过程与字符串类一样;但在恢复过程中,需要指定预期的数组大小:

#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 
#include <iostream> 
#include <fstream> 
#include <algorithm>
#include <iterator>
 
void save() 
{ 
	std::ofstream file("archive.xml"); 
	boost::archive::xml_oarchive oa(file); 
	int array1[] = {34, 78, 22, 1, 910};
	oa & BOOST_SERIALIZATION_NVP(array1); 
} 
 
void load() 
{ 
	std::ifstream file("archive.xml"); 
	boost::archive::xml_iarchive ia(file); 
	int restored[5]; // Need to specify expected array size
	ia >> BOOST_SERIALIZATION_NVP(restored);
	std::ostream_iterator<int> oi(std::cout, " ");
	std::copy(a, a+5, oi);
} 
 
int main() 
{ 
	save(); 
	load(); 
}

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<array1>
    <count>5</count>
    <item>34</item>
    <item>78</item>
    <item>22</item>
    <item>1</item>
    <item>910</item>
</array1>
</boost_serialization>

STL集合的序列化

对于列表和向量,在将信息加载回来的过程中,不需要提供任何大小和范围信息:

#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream> 
#include <fstream> 
#include <algorithm>
#include <iterator>
 
void save() 
{ 
	std::ofstream file("archive.xml"); 
	boost::archive::xml_oarchive oa(file); 
	float array[] = {34.2, 78.1, 22.221, 1.0, -910.88};
	std::list<float> L1(array, array+5);
	std::vector<float> V1(array, array+5);
	oa & BOOST_SERIALIZATION_NVP(L1); 
	oa & BOOST_SERIALIZATION_NVP(V1); 
}
 
void load() 
{ 
	std::ifstream file("archive.xml"); 
	boost::archive::xml_iarchive ia(file); 
	std::list<float> L2;
	ia >> BOOST_SERIALIZATION_NVP(L2); // No size/range needed
	
	std::vector<float> V2;
	ia >> BOOST_SERIALIZATION_NVP(V2); // No size/range needed
	
	std::ostream_iterator<float> oi(std::cout, " ");
	std::copy(L2.begin(), L2.end(), oi);
	std::copy(V2.begin(), V2.end(), oi);
}

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<L1>
    <count>5</count>
    <item_version>0</item_version>
    <item>34.200001</item>
    <item>78.099998</item>
    <item>22.221001</item>
    <item>1</item>
    <item>-910.88</item>
</L1>
<V1>
    <count>5</count>
    <item_version>0</item_version>
    <item>34.200001</item>
    <item>78.099998</item>
    <item>22.221001</item>
    <item>1</item>
    <item>-910.88</item>
</V1>
</boost_serialization>

自定义类型序列化

typedef struct date { 
	unsigned int m_day;
	unsigned int m_month;
	unsigned int m_year;
} date;

侵入式版本:在类定义中定义一个名为 serialize 的方法:

template<class Archive>
void serialize(Archive& archive, const unsigned int version)
{
    archive & BOOST_SERIALIZATION_NVP(m_day);
    archive & BOOST_SERIALIZATION_NVP(m_month);
    archive & BOOST_SERIALIZATION_NVP(m_year);
}

#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 
#include <iostream> 
#include <fstream> 
 
typedef struct date { 
    unsigned int m_day;
    unsigned int m_month;
    unsigned int m_year;
 
    date( int d,  int m,  int y) : m_day(d), m_month(m), m_year(y) 
    {}
    date() : m_day(1), m_month(1), m_year(2000) 
    {}
    friend std::ostream& operator << (std::ostream& out, date& d) 
    {
        out << "day:" << d.m_day
              << " month:" << d.m_month
    << " year:" << d.m_year;
        return out;
    }
    template<class Archive>
    void serialize(Archive& archive, const unsigned int version)
    {
        archive & BOOST_SERIALIZATION_NVP(m_day);
        archive & BOOST_SERIALIZATION_NVP(m_month);
        archive & BOOST_SERIALIZATION_NVP(m_year);
    }
} date;
 
void save() 
{ 
	std::ofstream file("archive.xml"); 
	boost::archive::xml_oarchive oa(file); 
	date d(15, 8, 1947);
	oa & BOOST_SERIALIZATION_NVP(d); 
} 
 
void load() 
{ 
	std::ifstream file("archive.xml"); 
	boost::archive::xml_iarchive ia(file); 
	date dr;
	ia >> BOOST_SERIALIZATION_NVP(dr); 
	std::cout << dr;
}

非侵入式版本:

namespace boost {
namespace serialization {
 
template<class Archive>
void serialize(Archive& archive, date& d, const unsigned int version)
{
    archive & BOOST_SERIALIZATION_NVP(d.m_day);
    archive & BOOST_SERIALIZATION_NVP(d.m_month);
    archive & BOOST_SERIALIZATION_NVP(d.m_year);
}
 
} // namespace serialization
} // namespace boost

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<d class_id="0" tracking_level="0" version="0">
    <d.m_day>15</d.m_day>
    <d.m_month>8</d.m_month>
    <d.m_year>1947</d.m_year>
</d>
</boost_serialization>

序列化版本控制

#include "boost/archive/binary_oarchive.hpp"  
#include "boost/archive/binary_iarchive.hpp"  
#include <iostream> 
#include <sstream> 
#include <fstream>

#define MAN     1
#define WOMAN   2
#define UNKNOW  3

class CPerson
{
public:
    CPerson()
    {
        ;
    }

    CPerson(size_t nBirthYear, std::string strName, size_t nGender)
        : m_nBirthYear(nBirthYear), m_strName(strName), m_nGender(nGender)
    {
        ;
    }

    ~CPerson()
    {
        ;
    }

    size_t GetBirYear() const
    {
        return m_nBirthYear;
    }

    std::string GetName() const
    {
        return m_strName;
    }

    size_t m_GetGender() const
    {
        return m_nGender;
    }

private:

    //要想序列化用户定义的类型 必须定义seriallze函数
    //serialzation不应该被显示调用 因为它仅在序列化或者反序列化的时候调用
    //应该声明为private的友元函数(不然boost::serialization访问不到)
    friend class boost::serialization::access;

    //serialize()提供了&操作符
    //使用&操作符就不需要再serialize中区分是序列化还是反序列化了
    template <typename Archive>
    void serialize(Archive &ar, CPerson &p, const unsigned int version);

private:
    size_t m_nBirthYear;
    size_t m_nGender;
    std::string m_strName;
};

template<typename Archive>
void CPerson::serialize(Archive & ar, CPerson &p, const unsigned int version)
{
    ar & p.m_nBirthYear;
    ar & p.m_strName;
    /*版本1之后存储了以下变量 低版本则使用默认值*/
    if (version >= 1)
    {
        ar & p.m_nGender;
    }
    else
    {
        p.m_nGender = UNKNOW;
    }
}

BOOST_CLASS_VERSION(CPerson, 1);
void Save()
{
    std::ofstream File("Data.bin");
    boost::archive::binary_oarchive oa(File);

    std::cout << "请输入名字" << std::endl;
    std::string strName;
    std::cin >> strName;

    std::cout << "请输入出生年份" << std::endl;
    size_t nBirthYear = 0;
    std::cin >> nBirthYear;

    std::cout << "请输入性别 1.男性  2.女性  3.未知" << std::endl;
    size_t nGender = 0;
    std::cin >> nGender;

    CPerson p(nBirthYear, strName, nGender);
    oa << p;
    File.close();
}

void Load()
{
    std::ifstream File("Data.bin");
    boost::archive::binary_iarchive ia(File);

    CPerson p;
    ia >> p;
    std::cout   << "姓名:"<< p.GetName() 
                << " 出生年份:" << p.GetBirYear()
                << " 性别代码:" <<p.m_GetGender() 
                << std::endl;
    File.close();
}

int main()
{
    int nTemp = 0;

    std::cout << "1.输入并存储  2.读取并显示" << std::endl;
    std::cin >> nTemp;

    switch (nTemp)
    {
    case 1:
        Save();
        break;
    case 2:
        Load();
        break;
    default:
        break;
    }

    system("pause");
    return 0;
}

版本控制的意义在于:随着class的参数的扩充,版本控制可以兼容旧版本的数据。version的值由宏BOOST_CLASS_VERSION指定,需要两个参数:一个是类名,一个是版本号。版本号默认为0,版本号只支持整型1个字节(0 - 255)。设置版本号之后,序列化会存储版本号,这样就能控制读取变量了。

#pragma once
#include"boost/archive/xml_iarchive.hpp"
#include"boost/archive/xml_oarchive.hpp"
#include"boost/serialization/vector.hpp"
#include"boost/serialization/list.hpp"
#include<fstream>
#include<iterator>
#include<algorithm>


class date
{
public:
	date(int d,int m,int y):m_day(d),m_month(m),m_year(y){}
	date() :m_day(1), m_month(1), m_year(1) {}
	~date(){}

	friend std::ostream& operator << (std::ostream& out, date& d) {
		out << "d.m_day:" << d.m_day << "-d.m_month:" << d.m_month << "-d.m_year:" << d.m_year << std::endl;
		return out;
	}


private:
	friend class boost::serialization::access;
	template<typename T>
	void serialize(T& archive, const unsigned int version) {
		archive & BOOST_SERIALIZATION_NVP(m_day);
		archive & BOOST_SERIALIZATION_NVP(m_month);
		archive & BOOST_SERIALIZATION_NVP(m_year);
	}
	unsigned int m_day;
	unsigned int m_month;
	unsigned int m_year;

};
#include<iostream>
#include"serialization_cusdata.h"
using namespace std;

void arrsave() {
	ofstream os("archieve.xml");
	boost::archive::xml_oarchive oa(os);
	int arr[] = {1,2,3,4,56,7,8};
	oa & BOOST_SERIALIZATION_NVP(arr);
	cout << "数组序列化完毕" << endl;

}
void vecsave() {
	ofstream os("archievec.xml");
	vector<int> vec = { 1,2,3,4,45,67,89 };
	boost::archive::xml_oarchive oa(os);
	oa & BOOST_SERIALIZATION_NVP(vec);
	cout << "vecsave()序列化完毕" << endl;
}


void arrload() {
	ifstream is("archieve.xml");
	boost::archive::xml_iarchive ia(is);
	int restroy[10];
	ia & BOOST_SERIALIZATION_NVP(restroy);
	ostream_iterator<int> oi(cout," ");
	copy(restroy, restroy + 7, oi);
	cout << "数组反序列化完毕" << endl;
}
void vecload() {
	ifstream is("archievec.xml");
	boost::archive::xml_iarchive ia(is);
	vector<int> inp;
	ia & BOOST_SERIALIZATION_NVP(inp);
	ostream_iterator<int> oa(cout," ");
	copy(inp.begin(), inp.end(), oa);
	cout << "vecload反序列化完毕" << endl;
}

void serialization_cusdata_test() {
	date da(8,3,2024);
	ofstream os("cusdata_serialization.xml");
	boost::archive::xml_oarchive oa(os);
	oa & BOOST_SERIALIZATION_NVP(da);
	cout << "serialization_cusdata_test()序列化完毕" << endl;
}
void serialization_cusdata_test_read() {
	ifstream is("cusdata_serialization.xml");
	boost::archive::xml_iarchive ia(is);
	date da;
	ia >> BOOST_SERIALIZATION_NVP(da);
	cout << da;

}


int main() {
	arrsave();
	arrload();
	vecsave();
	vecload();

	serialization_cusdata_test();
	serialization_cusdata_test_read();
	system("pause");
	return 0;
}
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Boost 库提供了非常强大的序列化和反序列化功能,可以用来将对象转换为二进制数据,以及从二进制数据还原为对象。以下是一个简单的示例代码,展示了如何使用 Boost 库进行序列化和反序列化: ```cpp #include <iostream> #include <fstream> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> class MyClass { public: int x; std::string name; // 序列化函数 template<class Archive> void serialize(Archive & ar, const unsigned int version) { ar & x; ar & name; } }; int main() { // 创建对象 MyClass obj; obj.x = 42; obj.name = "Boost"; // 序列化对象到文件 std::ofstream ofs("data.txt"); boost::archive::text_oarchive oa(ofs); oa << obj; ofs.close(); // 从文件反序列化对象 MyClass restoredObj; std::ifstream ifs("data.txt"); boost::archive::text_iarchive ia(ifs); ia >> restoredObj; ifs.close(); // 输出反序列化后的对象内容 std::cout << "Restored Object: " << std::endl; std::cout << "x: " << restoredObj.x << std::endl; std::cout << "name: " << restoredObj.name << std::endl; return 0; } ``` 在上述代码中,我们定义了一个名为 `MyClass` 的类,并在其中添加了 `serialize` 函数,该函数用于定义对象的序列化方式。我们使用 Boost 库中的 `text_oarchive` 类将对象序列化到文件中,并使用 `text_iarchive` 类从文件中反序列化对象。最后,我们输出反序列化后的对象内容。 请确保在编译时链接了 Boost 库,并将其头文件路径添加到编译器的包含路径中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

colorful_stars

您是我见过全宇宙最可爱的人!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值