在MFC中使用CArchive进行串行化数据
使用CArchive进行数据串行化非常的方便。
CArchive持有一个CFile对象,通过此对象进行读写,那么所有基于CFile的子类,都可以使用CArchive来进行串行化。
示例:
CFile file(_T("1.txt"), CFile::modeReadWrite); CArchive ar(&file, CArchive::load);
此时CArchive对象就是处于读取的状态,我们可以直接通过ar >> obj进行读取。
这里有一个要求,就是obj的类型必须是已经实现的operator >> 重载的类型。像CString,int,double这种,CArchive都已经实现了,可以直接使用。
这里有一个注意就是CArchive在串行化的时候,会向输出中添加以下其他信息,用来识别数据的类型,版本等。
那么来看一下如何让自定义的类型支持串行化,自定义的类型实现串行化,这里主要依靠operator >> 重载的CObject*的串行化版本。那么所有基于CObject的子类都可以实现串行化。
class MyDoc : public CObject { DECLARE_SERIAL(MyDoc); public: MyDoc() = default; MyDoc(int i, CString str); int m_i = 0; CString m_str = _T(""); public: virtual void Serialize(CArchive& ar); };
这里主要是有三点是必须要做的:
1、继承CObject
2、实现宏 DECLARE_SERIAL(MyDoc);
3、重现CObject的虚函数 virtual void Serialize(CArchive& ar);
4、编写默认构造函数。
#include "MyDoc.h" IMPLEMENT_SERIAL(MyDoc, CObject, 1 | VERSIONABLE_SCHEMA); MyDoc::MyDoc(int i, CString str):m_i(i),m_str(str) { } void MyDoc::Serialize(CArchive& ar) { CObject::Serialize(ar); if (ar.IsStoring()) { // storing code ar << m_i << m_str; } else { // loading code UINT schema = ar.GetObjectSchema(); switch (schema) { case 1: ar >> m_i >> m_str; break; default: AfxThrowArchiveException(CArchiveException::badSchema); break; } } }
首先看一下, IMPLEMENT_SERIAL(MyDoc, CObject, 1 | VERSIONABLE_SCHEMA); 这句话的意思,
此宏是DECLARE_SERIAL(MyDoc);的定义实现,通过前两个参数实现MyDoc与CObject的链接,后面1是版本号,宏VERSIONABLE_SCHEMA表示版本号是可变的。
版本号是什么意思呢,就是说如果我们的MyDoc对象在后期增加了数据成员,由于之前串行化的数据没有这个成员,那么版本号就起作用了,我们可以读取文件的版本号,来选择如何反序列化对象。如果老版本的串行化没有后期增加的数据成员,这里只需要反序列化已经有的数据,没有的做单独的初始化即可。
看一下虚函数的实现:
虚函数的实现首先串行化基类CObect对象,然后再串行化自身,这是常规的方式。
对于要序列化的MyDoc对象,这里可以直接使用CArchive对象进行串行化写入,那么在读取时,需要先获取文件的版本号,根据版本号进行操作。
下面是具体的使用例子:将MyDoc对象串行化。
try { CFile file(_T("1.txt"), CFile::modeReadWrite); CArchive ar(&file, CArchive::store); MyDoc* doc = new MyDoc(666,_T("hello,word!")); ar << doc; ar.Flush(); delete doc; } catch (CArchiveException* e) { e->ReportError(); e->Delete(); }
然后将对象反序列化:
try { CFile file(_T("1.txt"), CFile::modeReadWrite); CArchive ar(&file, CArchive::load); MyDoc* doc = nullptr; // new MyDoc; // 这里要注意,不能使用内存申请,CArchive会在内部为doc创建内存,这里如果new,就是内存泄露 ar >> doc; // 处理doc //。。。。。。。。。。。 delete doc; // CArchive不会自动释放该内存,需要手动释放。 } catch (CArchiveException* e) { e->ReportError(); e->Delete(); }
CArchive在串行化基于CObject的子类时,要注意,一定是指针,在反序列化时,对象必须是指针,用于接收内存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!