1、第11章 文档与串行化,MFC程序通过文档与串行化,可以非常方便的操作数据。我们可以把文档看做是数据的载体。当程序启动,从磁盘文件中读取对象数据,然后在内存中构建相应的对象。这种让对象数据持久性存在的过程就称之为串行化。本章主要学习CArchive类的使用和将一个类实现串行化功能,以及MFC程序读取、保存文档的执行流程等内容。,11.1 CArchive和Serialize,MFC提供的CArchive类实现了一种新的读写文件方式。我们可以通过CArchive类将对象数据保存到磁盘上或从磁盘上读取对象数据。如果CArchive类和Serialize()函数配合使用不仅可以体现CArchive类
2、功能的强大,而且使数据的加载和保存更加方便和清晰。,11.1.1 CArchive类介绍,我们可以把CArchive对象当成是一种二进制流。就像一个输入/输出流一样,把一个CArchive对象看成是文件之前的一个内存缓冲区。与输入/输出流不同的是,CArchive对象以一种有效的、非冗余的格式处理二进制对象数据。 CArchive对象不仅可以处理基本类型的数据,还可以处理CObject类的派生类对象。CArchive类重载了析取()和插入()操作符,为用户提供了一种方便的对象存档编程接口。在CArchive类中,这两种操作符都有多种重载形式。通过这些重载函数,我们可以利用CArchive对象来
3、完成文件的读写操作。,11.1.1 CArchive类介绍,CArchive类的声明如下所示。,11.1.2 CArchive类的使用,在程序中使用CArchive对象时,首先要创建一个CFile类或其派生类对象。又因为存档对象既可以用来加载数据,也可以用来保存数据,所以必须确保这个CFile类对象打开方式和CArchive对象的加载/保存状态相一致。 当要实例一个CArchive对象时,则需要将其与一个CFile类对象相关联。要注意,一个文件对象(CFile类对象)只能与一个存档对象(CArchive对象)相关联。下面我们通过编写一个处理员工信息的对话框程序,来展现CArchive类在处理多
4、组且不同类型数据时所表现的强大功能。,11.1.3 使一个类具备串行化能力,如果一个类的对象可以使用CArchive进行保存和加载,我们就称这个类可串行化。前面在第一小节我们提到CArchive不仅重载了各种类型的插入()操作符,而且还可以处理CObject类对象的数据。下面我们要对上一小节的程序进行改造,使CArchive存档对象实现对员工信息类对象的读取和保存。,11.1.3 使一个类具备串行化能力,如果要让一个对象有串行化(Serialize)能力,即能通过CArchive类进行存档和读取操作。必须满足下列5个条件,CObject只是其中之一。 从CObject派生下来。如此就可以具备好
5、多MFC特有的功能,如类型识别、动态创建等。 类声明中必须有DECLARE_SERIAL宏。此宏需要一个参数,即需要串行化类的名称。 类实现部分必须有IMPLEMENT_SERIAL宏。此宏需要三个参数,即类名称、基类名称和版本号。 改写Serialize()虚函数,使它能够适当的把类的成员变量写入文件。 此类必须有一个无参数的构造函数。因为若一个对象来自文件,MFC必须先动态创建它。而且在没有任何参数的情况下调用其构造函数,然后才从文件中读出对象数据。,11.1.4 在Serialize()函数中实现串行化,这一小节我们将继续对上面的例子进行改进。在CTest1Dlg类中改写Serializ
6、e()虚函数实现对数据的保存和读取操作,使代码更加条理化。因为在MFC中Serialize()函数其实就是数据读写的标志,也为后面章节中改写文档类程序的Serialize()函数做铺垫。,11.2 文档程序的串行化流程,串行化即Serialize,在文档程序中扮演着重要的角色。文档程序往往要处理大量的数据,然后通过视类来显示。这些数据的保存和加载都是通过文档类中的Serialize()函数来完成。了解Serialize()函数的来龙去脉可以使我们在利用Serialize()函数的时候更加得心应手。,11.2.1 新建文档流程,当我们单击文档程序工具栏上的“新建”按钮时,文档程序就会自动为我们创
7、建好一个视图窗口。在这一小节,我们将介绍它是怎么实现的,以及剖析MFC实现新建文档时的执行流程。 每当有一份文档产生时,总是会产生一个文档类对象、框架类对象和视类对象,由它们三个共同服务于即将处理的文档。将新建文档的调用顺序进行整理,如下图所示。,11.2.1 新建文档流程,11.2.2 保存文档流程,在上一节中,我们在对话框中进行保存和读取操作,都是通过在其消息响应函数中的代码完成的,包括最后一小节调用我们重写的Serialize()函数。读者已经知道在文档程序中,数据的保存也是通过文档类中的Serialize()函数完成的。但是,我们却在程序中找不到“保存”菜单项的命令消息响应函数。,11
8、.2.2 保存文档流程,将保存文档函数调用的顺序进行整理,如下图所示。,11.2.3 打开文档流程,上一小节,我们通过查看CDocument类源代码把MFC的Serialize保存文件操作已经弄清楚了。这一小节我们依旧通过查看源代码形式,来剖析文档程序打开文档操作是怎样的。 将打开文档函数之间的调用顺序进行整理,如下图所示。,11.2.3 打开文档流程,11.3 多文档程序中使用Serialize,虽然上一节我们通过分析MFC源代码知道了Serialize的来龙去脉,但相信读者对其使用流程还是很茫然。这一节我们将以举例子的方式展示使用Serialize给数据存储带来的便利。,11.3.1 单一
9、类型数据的存储和读取,单一类型的数据存储非常简单,直接在Serialize()函数中利用CArchive类重载的插入()即可完成数据保存和读取操作。下面我们举一个利用Serialize()函数存储CString单一类型变量的例子。,11.3.2 类对象的存储和读取,在实际编写文档程序时往往存储的数据不是单一类型的。为了使数据统一和独立,我们往往用类来封装一组类型的数据。这时,在使用Serialize()函数存储数据的时候就不是那么简单了。下面我们通过封装好的一个员工信息类,来实现多文档程序中类的串行化操作。 既然我们要处理的是员工档案,每一个员工所涉及的数据种类是很多的。这时我们可以用一个员工
10、信息类来封装员工信息,如同11.1.3节所述。这里为了简化程序,我们只是将姓名和年龄两种不同类型的变量封装到类中,来演示类对象的存储和读取操作。,11.4 小结,本章首先利用对话框程序详细的介绍了CArchive类的使用,以及和Serialize()函数配合实现数据的保存和读取功能,然后又讲解了多文档程序中新建、保存、打开文档的执行流程,最后我们总结了文档程序中使用Serialize()函数进行文件存取的一般步骤。本章说讲内容皆为重点,尤其是CArchive类和Serialize()函数的使用。难点是读者能够理清文档程序中保存和打开操作的流程,其实道理就如同前面对话框例子中的“保存”和“读取”按钮一样。,