序列化是指对象将其状态保存在一个字节流中,并用该字节流重建对象。实例化实现了文档数据的保存和装入的幕后工作,MFC通过序列化实现了应用程序的文档读写功能。
序列化的基本思想是:一个类应该能够对自己的成员变量的数据进行读写操作,对象可以通过读操作而重新创建。即对象可以将其当前状态(由其成员变量的值表示)写入永久性存储体(通常指磁盘)中,以后可以从永久性存储体中读取(载入)对象的状态,从而重建对象。类的对象自己应该具备将状态值写入磁盘或从磁盘中读出的方法(即成员函数),这种对象的保存和恢复过程称为序列化。
文档数据的序列化操作通过CArchive类对象作为中介来完成。CArchive类对象由应用程序框架创建,并与用户正在使用的文件关联在一起。
CArchive类对象为读写CFile类对象中的可序列化数据提供了一种安全的缓冲机制,它们之间形成了如下关系:
Serialize()函数 <-->CArchive类对象 <--> CFile类对象 <-->磁盘文件
一个可序列化的类必须有一个称作为序列化的成员函数Serialize(),它是CObject类提供的虚函数。由于应用程序的数据一般由文档对象来管理的,因此文档的序列化常在文档类的成员函数Serialize()中进行。当用户选择文件菜单中的New、Open、Save和Save as 等菜单命令时,都会调用文档类的派生类的成员函数Serialize(),实现与序列化有关的操作。
例如某类A为永久化类,具体编码过程如下:
Class A:CObject //必须以CObject或其派生类为基类
{
DECLARE_SERIAL(A); //声明了序列化
private:
int m_X,m_Y;
...
public:
Serialize(CArchive&ar); //重写序列化虚函数
};
重写的序列化函数Serialize的实现:
A::Serialize(CArchive &Aar)
{
if(ar.IsStoring()) //存储数据
{
Aar<<m_X;
Aar<<m_Y;
}
else //读取数据
{
Aar>>m_X;
Aar>>m_Y:
}
}
CArchive类对象是单向(单工)的,即不能通过一个CArchive类对象既进行文档的保存,又进行文档的读取。通过调用CArchive类的成员函数IsStoring()来检索当前CArchive类对象的属性。如果CArchive类对象是用于写数据,函数IsStoring()返回TRUE;如果CArchive类对象是用于读数据,函数IsStoring()返回FALSE。
CArchive类对象使用重载的插入(<<)和提取(>>)操作符执行读和写操作。这种方式与cin和cout中的输入输出流非常相似,只是这里处理的是对象,而cin和cout处理的是ASCII字符串。
注意,MFC应用程序文件的序列化与其他不使用MFC序列化程序的文件格式并不兼容。若读写一般格式的文件,如TEXT,可直接使用CFile类及其派生类。
实现序列化的主要工作就是设计序列化的类。MFC应用程序实现类的序列化必须满足以下4个条件:
(1)类必须直接或间接地从CObject类派生而来;
(2)类必须定义一个不带参数的构造函数,当从磁盘文件载入文档时调用该构造函数来创建一个可序列化的对象,使用从文件中读出来的数据填充对象的成员变量;
(3)在类的头文件中使用DECLARE_SERIAL宏,在类的实现文件中使用IMPLEMENT_SERIAL宏;
(4)在自定义类中重载序列化成员函数Serialize()
实例:
//---------------------------------------------
// Book.h
//---------------------------------------------
#include <afxwin.h>
class CBook : public CObject
{
DECLARE_SERIAL(CBook)
public:
CString m_strName;
CString m_strAuthor;
CString m_strPress;
public:
CBook()
{
// 要使CBook对象实现序列化,必须定义默认构造函数
}
CBook(CString strName, CString strAuthor, CString strPress)
{
m_strName = strName; // 书名
m_strAuthor = strAuthor; // 作者
m_strPress = strPress; // 出版社
}
void Serialize(CArchive &); // 重载基类的Serialize函数
};
//---------------------------------------------
// Book.cpp
//---------------------------------------------
#include "Book.h"
IMPLEMENT_SERIAL(CBook, CObject, 1)
void CBook::Serialize(CArchive &ar)
{
CObject::Serialize(ar);
if(ar.IsStoring())
{
ar << m_strName << m_strAuthor << m_strPress;
}
else
{
ar >> m_strName >> m_strAuthor >> m_strPress;
}
}
主程序:
CBook book1("Programming Windows", "Charles Petzold", "Microsoft Press");
CBook book2("Programming Windows with MFC", "Jeff Prosise", "Microsoft Press");
int nCount = 2;
// 序列化
CFile fileStore(_T("mybooks.dat"), CFile::modeWrite | CFile::modeCreate);
CArchive arStore(&fileStore, CArchive::store);
CBook* pBooksStore[2] = { &book1, &book2 };
arStore << nCount;
for (int i=0; i<nCount; ++i)
{
arStore << pBooksStore[i];
}
fileStore.Close();
// 反序列化
CFile fileLoad(_T("mybooks.dat"), CFile::modeRead);
CArchive arLoad(&fileLoad, CArchive::load);
arLoad >> nCount;
CBook* pBooksLoad = new CBook[nCount];
for (int i=0; i<nCount; ++i)
{
arLoad >> pBooksLoad[i];
}
fileLoad.Close();