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.在反序列化的時候,我發現如果文件爲空,反序列化會出現問題,所以上面的代碼做了一個判斷

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