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

image.png

②报错

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

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


image.png


使用

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

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

#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.在反序列化的时候,我发现如果文件为空,反序列化会出现问题,所以上面的代码做了一个判断

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容