当前位置: 首页 > news >正文

MFC:初步理解序列化与反序列化(含代码实现)

       序列化与反序列化是MFC将对象数据以二进制数据流的形式进行存储和读取的机制,读、写的效率很高。通过序列化与反序列化,可以将程序中对象在内存中数据保存到文件 (磁盘) 或者从文件 (磁盘) 中读取到内存以恢复对象数据,从而实现程序对数据的持续管理。其中,序列化是指从内存到文件 (硬盘) 的存储操作;而反序列化则是指从文件 (硬盘) 到内存的读取操作。
       其程序实现的基本思路是利用文档类对象维护内存中数据,利用文件类对象维护硬盘文件数据,将二者联系起来的是归档类对象;利用这三个类的相互关联实现序列化 (含反序列化)目的。
一、序列化、反序列相关类及作用
       1、文档类CDocument,顾名思义,这个类是MFC中专职管理数据的类。而所谓序列化反序列化的概念也是针对这个类而言的,我们在这个类内可以进行序列化(含反序列化)声明,序列化声明及实现是其它所有操作的前提条件。
       通过构造继承自CDocument的自定义类,用其成员变量作为序列化或反序列化数据在内存中的载体,并通过重写它的成员虚函数Serialize实现序列化或(反序列化的具体操作,归档类对象作为参数被引入,实现文档类与归档类的关联。
       2、文件操作类CFile,作用是完成硬盘文件的读、写、存操作。成员函数包括Open (打开
文件)、Read (读文件)、Write (写文件)、Close (关闭文件) 等。文件操作类对象作为参数被归档类对象构造函数引入,与归档类对象实现关联。
       3、归档类CArchive,是用于数据流的封装类,完成内存数据的二进制读、写操作。归档类
对象首先被文档类虚函数Serialize作为参数引入;接下来,CArchive的构造函数通过其第一个
参数与文件类建立联系;并使用重载的">>"、"<<"进行读取与写入操作。CArchive对象和CFile对
象一样,用毕也需调用close函数关闭。归档类对象也有自己的成员函数,如IsStoring等。归档
类对象在三个类之间起中介作用。
二、代码实现
       这里的代码是基于VS2022 C++空项目调用MFC静态库编制的,头文件中需要包含MFC要求
的<afxwin.h>;使用的字符集为多字符集;运行结果显示在控制台窗口。具体步骤为:
1、类的声明及相关函数等的实现
      a、公开继承 CDocument 类声明一个文档类对象;
      b、类内进行序列化声明并在类外实现;
      c、类内public方式声明对象成员变量,这些成员变量是进行序列化 \ 反序列化的载体;
      d、类内声明文档类对象构造函数并在类外实现,构造函数用于接收输入数据;
      e、类内声明重写Serialize序列化虚函数并在类外实现。重写虚函数的目的是为了在
文档类与CArchive类之间建立关联,CArchive对象以参数形式进入虚函数。
2、序列化实现过程(子程序)
     a、使用CFile类对象调用Open函数创建或打开文件,文件打开方式与归档类对象读写状态
          要一致;
     b、使用CArchive类及构造函数定义归档类对象;
     c、将屏幕输入数据保存进文档类对象;
     d、使用CAchive对象将文档类对象数据写入文件;
     e、调用Close函数关闭归档类对象;
     f、调用Close函数关闭文件类对象。
3、反序列化实现过程(子程序)
     a、使用CFile类对象调用Open函数创建或打开文件 ;
     b、使用CArchive类及构造函数定义归档类对象;
     c、定义文档类指针对象;
     d、使用CAchive对象将文件数据读取到内存并转给文档类对象
     e、利用文档类对象接收数据进行屏幕显示
     f、调用Close函数关闭归档类对象
     g、调用Close函数关闭文件对象
4、主函数实现
三、代码实现及相关注释
    

#include<afxwin.h>
#include<iostream>
using namespace std;
//公开继承CDocument方式声明文档类并构造用于存储或读取的数据类型
class CMyDoc :public CDocument
{ DECLARE_SERIAL(CMyDoc) //序列化(含反序列化)声明
public:CString m_Name; //成员变量int m_Age;CString m_Addr;CMyDoc(CString name = "", int age = 0, CString addr = ""); //声明构造函数用于赋值virtual void Serialize(CArchive& ar); //声明重写Serialize虚函数
};
//类外实现序列化(含反序列化)
IMPLEMENT_SERIAL(CMyDoc, CDocument, 2) //参3 为版本号随意定或NULL
//类外实现构造函数
CMyDoc::CMyDoc(CString name, int age, CString addr) //此处不再需要缺省值
{this->m_Name = name;this->m_Age = age;this->m_Addr = addr;
}
//类外实现重写Serialize虚函数(CArchive对象为参数)
void CMyDoc::Serialize(CArchive &archive) 
{if (archive.IsStoring()) //归档类成员函数IsStoring返回是否写入{archive << m_Name << m_Age << m_Addr;  //写入}else {archive>> m_Name >> m_Age >> m_Addr; //读取}
}
//序列化实现子程序
void dataStore() 
{ CFile file; //声明文件类对象file.Open("C:\\Users\\Administrator\\Desktop\\serial.txt", CFile::modeCreate | CFile::modeWrite,NULL);//CFile类成员函数Open:参1 文件名 参2 打开模式(文件不存在则创建、写模式) 参3 接收错误信息指针//文件后缀虽然写的是txt,但存储内容是二进制格式while (TRUE){CArchive myCAr(&file, CArchive::store, 4096, NULL); //CAchive类构造函数,此函数将CArchive对象与CFile对象连接//参1 CFile对象的指针 参2 归档状态存入 参3 缓冲区大小(默认4096) 参4 指向缓冲区的指针(缺省填NULL)cout << "在姓名处输入xxxxx退出" << endl;cout << "请输入姓名:" ;char name[64];cin >> name;if (name[0]=='x'&& name[1] == 'x'&& name[2] == 'x'&& name[3] == 'x'&& name[4] == 'x') break;cout << "请输入年龄:" ;int age;cin >> age;char addr[128];cout << "请输入住址:";cin >> addr;CMyDoc data(name, age, addr); //将输入数据保存仅文档类对象myCAr << &data; //将文档类对象传入CArchive对象(序列化)myCAr.Close(); //关闭CArchive对象}file.Close(); //关闭文件类对象
}
//反序列化子程序
void dataLoad() 
{CFile file;file.Open("C:\\Users\\Administrator\\Desktop\\serial.txt", CFile::modeRead,NULL);//各参数含义同dataStore(),只是参2为只读模式CArchive myCAr(&file, CArchive::load, 4096);//各参数含义同dataStore(),只是参2 为读取状态CMyDoc* pData = NULL; //定义文档类指针对象用来接收读取的数据while(TRUE){try {  //连续从CArchive对象读取数据传给文档类对象并进行显示myCAr >> pData; cout << pData->m_Name << " " << pData->m_Age << " " << pData->m_Addr << endl;} catch (...) { break; }} myCAr.Close(); //关闭CArchive对象file.Close(); //关闭文件类对象
}
//主函数
int main() 
{dataStore();dataLoad();system("pause");return 0;
}
/*
运行结果:
在姓名处输入xxxxx退出
请输入姓名:张三
请输入年龄:25
请输入住址:天津和平
在姓名处输入xxxxx退出
请输入姓名:李四
请输入年龄:36
请输入住址:天津红桥
在姓名处输入xxxxx退出
请输入姓名:王五
请输入年龄:27
请输入住址:天津河西
在姓名处输入xxxxx退出
请输入姓名:xxxxx
张三 25 天津和平
李四 36 天津红桥
王五 27 天津河西
请按任意键继续. . .
*/

相关文章:

  • 【机器学习】之 K-最近邻(KNN)算法原理及实现
  • 【JAVA WEB实用与优化技巧】如何使用本地.bat/.sh脚本快速将服务发布到测试环境?
  • NVIDIA发布重磅AI创新,黄仁勋在COMPUTEX大会预示计算未来
  • 面向对象程序设计之从C到C++的初步了解
  • 奶茶店、女装店、餐饮店是高危创业方向,原因如下:
  • 一个知识问答系统,用户的选择决定接下来出现的问题,且下一个问题的呈现取决于前面几个问题的回答
  • 工业4.0利器:MES系统
  • 在一个定义好的数据对象(class)中,后续更新时只更新其中部分数据,其余部分会恢复初始设置吗
  • Amazon云计算AWS(四)
  • typescript --object对象类型
  • 开发和渗透偷懒利器utools
  • 鲁教版七年级数学下册-笔记
  • OCR图片转Excel表格:没结构化的弊端
  • JS(DOM、事件)
  • 【MyBatis】MyBatis操作数据库(二):动态SQL、#{}与${}的区别
  • CSS实用技巧干货
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • Javascript Math对象和Date对象常用方法详解
  • Linux后台研发超实用命令总结
  • Meteor的表单提交:Form
  • mysql 5.6 原生Online DDL解析
  • Next.js之基础概念(二)
  • nodejs:开发并发布一个nodejs包
  • overflow: hidden IE7无效
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • SpiderData 2019年2月16日 DApp数据排行榜
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 移动端解决方案学习记录
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​2021半年盘点,不想你错过的重磅新书
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (k8s)kubernetes 部署Promehteus学习之路
  • (ZT)薛涌:谈贫说富
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .Net Core和.Net Standard直观理解
  • .NET6实现破解Modbus poll点表配置文件
  • .NetCore 如何动态路由
  • .NET开源项目介绍及资源推荐:数据持久层
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • @selector(..)警告提示
  • @Transactional事务注解内含乾坤?
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [C++] 容器适配器:深入理解Stack与Queue的底层原理
  • [C++]指针与结构体
  • [C++初阶]vector的初步理解