C++使用Boost序列化对象

前言

在做运动员管理系统的时候,我用到C++中的对象遇到一个问题,就是保存对象的时候,想要将对象保存保存在文件中,本来是直接这样子:

       int count = 0;//对象个数,即学生人数
      fstream infile("e:\\student.txt",ios::in | ios::binary);//以读方式打开文件
      if (!infile)
      {
          cout<<"open file error!"<<endl;
          getchar();
          exit(0);
     }
     Student stu;
     while (infile.read((char*)&stu,sizeof(stu)))//强制类型转换为(char*),
     {
         count++;
     }
     infile.close();
     return count;
	 
	 //写入
	 Student stu1;
            stu1.InputInfo();
            fstream outfile("e:\\student.txt", ios::app | ios::binary);//这里以app方式打开文件进行添加
            if (!outfile)
            {
                cerr << "open file error!";
            }
            outfile.write((char*)&stu1, sizeof(stu1));
            outfile.close();

这是读的例子,写的话也是很简单的,总体的思路是利用文件流的write或者read函数,
第一个参数给的是缓存的地址,我们先取到对象的地址,然后将其转化成字符指针类型,
然后给一个大小,也就是,对象最后就会以一定的大小以二进制的形式保存在了文件,我们再读的时候然后根据指定的大小去读就好。

但是接下来就会遇到一些问题,我写之后,string对象虽然能写入文件,但是,问题是string对象里面是有一个成员维护着一段内存,放的是这段内存的地址,那么写入的时候,也是写的这段地址而不是值,那么下次读出来的时候,这个地址指向的地方很可能已经被释放了,所以会报错,所以我用了另外一个方法,使用boost来序列化和反序列化对象,这里不会过多讲关于序列化对象的技术实现原理,大多是怎么使用boost。


(反)序列化对象

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

简单来讲就是将对象的状态信息转化成字节流的形式然后做一个传输和存储,若以二进制的形式存在,对象的保真度高
同样,我们将字节流转成对象的状态信息的时候就是反序列化

如果知道JSON的话,其实有时候我们就是将对象的信息序列化成JSON格式然后进行传输

Boost使用

Boost是C++的一个很强大的标准类库,这里不做过多介绍

安装

网上有很多的安装方法,可以去官网下载,然后自己配置好环境变量,这里介绍一种最简单的

①使用VS的Nuget

②报错

如果安装完成之后,发现使用的时候会报错,比如这样:
libboost_serialization-vc90-mt-gd-1_62.lib 打不开这个文件
可以参考这个:https://blog.csdn.net/qq_17044529/article/details/82535191

分析报错原因会发现是缺少libbost_serialization…这个文件,简单来讲,boost在编译的时候可能要依赖这个文件,所以我们还要下载一个文件


使用

我这里结合一个自定义的类来说明使用方法:

需要导入的文件(部分重要的)

#include <boost/archive/binary_iarchive.hpp> //二进制序列化
#include <boost/archive/binary_oarchive.hpp> //二进制序列化
#include <boost/serialization/vector.hpp> //序列化STL容器要导入
#include<boost/serialization/map.hpp> //序列化STL容器要导入

Events类 (不是完整的)

class Events {
	private:	
		//项目名
		string eventname;
		//eventid
		string eid;
		//开始时间
		string starttime;
		//地点
		string location;
		//这个比赛进行的阶段(0代表初赛,1代表决赛)
		string statusforevent;
		//参加该项目的运动员信息
		string genderforevent;
		//这个项目是否被取消
		string is_canceled;
		//这个项目的参赛人员,管理员才能看到,而且这里面保存的是player的uid,这样就没必要把player一个个保存在events这个文件(表)里面了
		vector<string> players;		
		//因为对象引用没有空的概念,所以自定义是否为空的状态
		int is_null = 0;
		}

我将这个类的成员变量全部设置成为了private,那么如果想要序列化的话,我们首先要在这个类中声明一个友元类(如果是public就不必了)

friend class boost::serialization::access;

接下来最重要的是我们需要声明模板函数

		template<class Archive>
		void serialize(Archive & ar, const unsigned int version)
		{
			ar& eid;
			ar& starttime;
			ar& location;
			ar& statusforevent;
			ar& genderforevent;
			ar& is_canceled;
			ar& eventname;
			ar& players;
			ar& is_null;
		}

以上就是要做的所有前期准备

.cpp中的boost的使用

序列化对象(写入文件)

ofstream fout("Events.txt", ios::binary);	
	if (fout.is_open()) {		
		boost::archive::binary_oarchive oa(fout);
		oa << events;
		fout.close();
		return true;
	}
	else {
		cout << "打开失败" << endl;
		return false;
	}			

反序列化(读取文件)

//首先判断文件是否为空
	ifstream fin("Events.txt", ios::in|ios::binary);	
	fin.seekg(0, ios::end);
	streampos fp = fin.tellg();	
	if (fin.is_open()&&fp) {	
		//然后要把文件指针放到文件头部
		fin.seekg(0);
		boost::archive::binary_iarchive ia(fin);
		ia >> events;

		//event对象信息填写
		event.eid = data["eid"];
		event.eventname = data["eventname"];
		event.starttime = data["starttime"];
		event.genderforevent = data["genderforevent"];
		event.is_canceled = data["is_canceled"];
		event.location = data["location"];
		event.statusforevent = data["statusforevent"];
		event.players.push_back(data["player"]);

		events.insert(pair<string, Events>(event.eid, event));		
		fin.close();
	}				

注意

1.如果你想要序列化STL中的对象,比如vector,那么你还需要导入boost中的特定类:
#include <boost/serialization/vector.hpp>
其他同理


2.如果你vetor中的类没有写模板方法,那么会报错,比如:
vector<player> players
player这个类中也要做相同的前期准备

3.在反序列化的时候,我发现如果文件为空,反序列化会出现问题,所以上面的代码做了一个判断

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章