MFC序列化Serialize

使用原因

写一个http下载软件,要求退出时保存未下载的记录,下次启动继续下载,我的下载记录保存在程序中的一个list中,用序列化实现是比较方便的。

序列化Serialize使用介绍

创建可序列化的类

使类可序列化需要五个主要步骤。下面列出了这些步骤并在以后章节内进行了解释:

  1. 从 CObject 派生类(或从 CObject 派生的某个类中派生)。
  2. 重写 Serialize 成员函数
  3. 使用 DECLARE_SERIAL 宏(在类声明中)。
  4. 定义不带参数的构造函数
  5. 为类在实现文件中使用 IMPLEMENT_SERIAL 宏

如果直接调用 Serialize 而不是通过 CArchive 的“>>”和“<<”运算符调用,则序列化不需要最后三个步骤。

从 CObject 派生类

在 CObject 类中定义了基本的序列化协议和功能。正如在 CPerson 类的下列声明中所示,通过从 CObject 中(或从 CObject 的派生类中)派生类,可获得对 CObject 的序列化协议及功能的访问权限。

重写 Serialize 成员函数

在 CObject 类中定义的 Serialize 成员函数实际上负责对捕获对象的当前状态所必需的数据进行序列化。Serialize 函数具有 CArchive 参数,该函数使用其来读写对象数据。CArchive 对象具有成员函数 IsStoring,该成员函数指示 Serialize 正在存储(即正在写入数据)还是正在加载(即正在读取数据)。用 IsStoring 的结果作为参考,使用输出运算符 (<<) 将对象数据插入到 CArchive 对象中或使用输入运算符 (>>) 提取数据。

假定一个类是从 CObject 派生的并具有两个新成员变量,分别为 CString 和 WORD 类型。下列类声明段显示了新成员变量和重写的 Serialize 成员函数的声明:

class CPerson : public CObject
{
public:
    DECLARE_SERIAL( CPerson )
    // empty constructor is necessary
    CPerson(){};

    CString m_name;
    WORD   m_number;

    void Serialize( CArchive& archive );
    
    // rest of class declaration
};

重写 Serialize 成员函数

  1. 调用 Serialize 的基类版本以确保序列化对象的继承部分。
  2. 插入或提取您的类所特定的成员变量。

    输出运算符及输入运算符与存档类交互作用以读写数据。下面的示例显示了如何实现以上声明的 CPerson 类的 Serialize

    void CPerson::Serialize( CArchive& archive )
    {
        // call base class function first
        // base class is CObject in this case
        CObject::Serialize( archive );
    
        // now do the stuff for our specific class
        if( archive.IsStoring() )
            archive << m_name << m_number;
        else
            archive >> m_name >> m_number;
    }
    

也可使用 CArchive::Read 及 CArchive::Write 成员函数来读写大量未键入的数据。

使用 DECLARE_SERIAL 宏

在支持序列化的类的声明中需要 DECLARE_SERIAL 宏,如下所示:

class CPerson : public CObject
{
    DECLARE_SERIAL( CPerson )
    // rest of declaration follows...
};

定义不带参数的构造函数

反序列化对象(从磁盘上加载)后,MFC 重新创建这些对象时,需要一个默认的构造函数。反序列化进程将用重新创建对象所需的值填充所有成员变量。

可将该构造函数声明为公共的、受保护的或私有的。如果使该构造函数成为受保护的或私有的,请确保它将仅由序列化函数使用。该构造函数必须使对象处于这样一种状态:必要时,可允许将其安全删除。

注意   如果忘记在使用  DECLARE_SERIAL 及  IMPLEMENT_SERIAL 宏的类中定义不带参数的构造函数,将在使用  IMPLEMENT_SERIAL 宏的行上得到“没有可用的默认构造函数”编译器警告。

在实现文件中使用 IMPLEMENT_SERIAL 宏

IMPLEMENT_SERIAL 宏用于定义从 CObject 中派生可序列化类时所需的各种函数。在类的实现文件 (.CPP) 中使用这个宏。该宏的前两个参数是类名和直接基类的名称。

该宏的第三个参数是架构编号。架构编号实质上是类对象的版本号。架构编号使用大于或等于零的整数。(请不要将该架构编号与数据库术语混淆。)

MFC 序列化代码在将对象读取到内存时检查该架构编号。如果磁盘上对象的架构编号与内存中类的架构编号不匹配,库将引发 CArchiveException,防止程序读取对象的不正确版本。

如果要使 Serialize 成员函数能够读取多个版本(即,读取用应用程序的不同版本写入的文件),可将 VERSIONABLE_SCHEMA 值作为 IMPLEMENT_SERIAL 宏的参数。有关用法信息和示例,请参见 CArchive 类的 GetObjectSchema 成员函数。

以下示例显示了如何将 IMPLEMENT_SERIAL 用于从 CObject 派生的 CPerson 类。

IMPLEMENT_SERIAL( CPerson, CObject, 1 )

正如序列化:序列化对象文章中所讨论的,一旦具有可序列化的类,就可以序列化类的对象。

序列化与反序列化

程序启动时,从文件中反序列化出保存的list(注意fi.open,第一次程序运行是没有保存过序列化文件的,所以判断open是否成功再进行反序列化)
//反序列化
	CFile fi;
	if (fi.Open(m_strProgramPath+"download.tmp", CFile::modeRead))
	{
		CArchive ar(&fi, CArchive::load);
		Serialize(ar); //反序列化对象
		ar.Close();
		fi.Close();
	}
程序关闭时,将list 序列化保存到文件中
//序列化保存
	CFile fi;
	fi.Open(m_strProgramPath+"download.tmp", CFile::modeCreate|CFile::modeWrite); //如果文件不存在则创建一个,否则只是往文件写数据
	CArchive ar(&fi, CArchive::store);
	Serialize(ar);   //序列化对象
	ar.Close();
	fi.Close();
序列化类中的Serialize实现如下:
void CTMDownloadCtrl::Serialize( CArchive& archive )
{
	// call base class function first
	// base class is CObject in this case
	CObject::Serialize( archive );

	// now do the stuff for our specific class
	if( archive.IsStoring() )
	{
		//序列化
		archive << m_lsDownloadUrl.size();
		for (list<DOWNLOADDATA>::iterator it = m_lsDownloadUrl.begin();
			it != m_lsDownloadUrl.end();it++)
		{
			archive << it->strFileName;
			archive << it->strUrl;
		}
	}
	else
	{
		//反序列化
		int nSize = 0;
		archive >> nSize;

		for (int i=0;i<nSize;i++)
		{
			DOWNLOADDATA dd;
			archive >> dd.strFileName;
			archive >> dd.strUrl;
			m_lsDownloadUrl.push_back(dd);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Barry__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值