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 天津河西
请按任意键继续. . .
*/

相关推荐

  1. MFC初步理解序列序列代码实现

    2024-06-07 21:42:01       29 阅读
  2. 序列序列

    2024-06-07 21:42:01       47 阅读
  3. 手撕代码: C++实现数据的序列序列

    2024-06-07 21:42:01       29 阅读
  4. 序列序列xml bin

    2024-06-07 21:42:01       53 阅读
  5. Springboot Jackson 序列序列配置

    2024-06-07 21:42:01       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 21:42:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 21:42:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 21:42:01       82 阅读
  4. Python语言-面向对象

    2024-06-07 21:42:01       91 阅读

热门阅读

  1. 大数据面试题第二期*6

    2024-06-07 21:42:01       29 阅读
  2. 查看Hive表的描述信息,包括在HDFS上的Location信息

    2024-06-07 21:42:01       26 阅读
  3. 东方博宜1760 - 整理抽屉

    2024-06-07 21:42:01       31 阅读
  4. 详解布隆过滤器,实现分布式布隆过滤器

    2024-06-07 21:42:01       33 阅读
  5. 【数据库系统概论】数据库设计过程

    2024-06-07 21:42:01       34 阅读
  6. Python 正则表达式:深入解析匹配多个模式

    2024-06-07 21:42:01       26 阅读
  7. Alsa UCM

    Alsa UCM

    2024-06-07 21:42:01      23 阅读
  8. 使用 .NET Core 实现微服务(带例子)

    2024-06-07 21:42:01       30 阅读
  9. MySQL-6、单表访问方法

    2024-06-07 21:42:01       30 阅读
  10. 2003NOIP普及组真题 4. 麦森数

    2024-06-07 21:42:01       31 阅读