按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
于是将 CSampleData::Serialize()函数代码修改为:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar m_strName 》》 m_nType; //读取数据
}
}
在上面的代码中,首先调用基类的 Serialize()函数进行基类的序列化,保证保存和装入的
数据的正确性。
Serialize()函数具有 CArchive 参数 ar 的特性,即读写对象数据。CArchive 对象中包括成
·178 ·
…………………………………………………………Page 190……………………………………………………………
第 8 章 文件操作
员函数 IsStoring(),该成员函数返回值为 TRUE 时表示 Serialize()正在存储(即正在写入数据 ),
反之则表明正在加载(即正在读取数据 )。用 IsStoring() 的结果作为参考,使用输出运算符(》 )提取数据。这也反映了 MFC 串
行化的顺序性,即不能进行随机的读写操作,一次调用只能读取或只能保存。
在串行化代码中需要对各种数据类型进行处理,主要分为下列几种情况。
(1)固有数据类型
CArchive 类的插入运算符(》 )对许多 C++ 固有的数据类型进行了
重载,可以直接使用。例如在上面的程序中要对 int 的成员变量 m_nType 进行串行化,即可
直接使用插入运算符和提取运算符。下面列出一些被 CArchive 类默认支持的数据类型:
o BYTE :8 位无符号整数。
o WORD :16 位无符号整数。
o LONG :32 位带符号整数。
o DWORD :32 位无符号整数。
o float:单精度浮点数。
o double :双精度浮点数。
o int :32 位带符号整数。
o short:16 位带符号整数。
o char :8 位字符类型。
o unsigned :32 位无符号整数。
(2 )CString 和 CRect 等类型
CString 和 CRect 等类型,虽然不是从 CObject 派生的类,但是它们有自己针对 CArchive
类的重载插入运算符和提取运算符,因此也可以直接使用这两个运算符进行串行化。
(3 )自定义的类
如果序列化的类中包含其他自定义的内嵌对象,则需要处理后再进行串性化。例如在
CSampleData 类中添加如下的新数据成员:
public:
CSampleChildData m_data;
将 CSampleData 类串行化时,需要对 CSampleChildData 进行额外的处理。首先使得
CSampleChildData 继承 CObject,然后编写它自己的 Serialize()成员函数。这时 CSampleData
类的 Serialize()函数可以进行如下修改以实现对 m_data 的串行化:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar m_strName 》》 m_nType; //读取数据
}
·179 ·
…………………………………………………………Page 191……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
m_Data。Serialize(ar); // 串行化 m_Data
}
如果 CSampleData 类中的 CSampleChildData 对象是通过指针在堆中创建的,则代码如下:
public:
CSampleChildData *m_pData;
将 CSampleData 类串行化更为简单。首先需要为 CSampleChildData 添加串行化代码,即
继承 CObject,并添加相应的宏和构造函数,最后编写 CSampleChildData 自己的 Serialize()
函数。完成对 CSampleChildData 的修改后就可以在 CSampleData 类的 Serialize()函数中用
CArchive 的插入和提取运算符进行串行化。代码如下:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar 》 m_nType 》》 m_pData; //读取数据
}
}
在上述代码 中,之所以 能对自定义 的类进行插 入和提取运 算,是因为 在添加的
DECLARE_SERIAL()和 IMPLEMENT_SERIAL()宏中包含了对插入和提取运算符的重载 。当
CSampleChildData 对象被写进文件时,这两个宏保证类名和数据一起被写进去 ;而当从文件
中读入时,类名被读进来,相应的类的对象被动态构造,这些也是由这两个宏包含的代码实
现的。当 CSampleChildData 对象被构造后,就可以通过 Serialize() 自动进行串行化,这是由
于 CArchive 的插入和提取运算符对 CObject 类型进行了重载。最后新建的 CSampleChildData
对象的指针即保存在 m_pData 中。根据上面的分析,对于自定义的类,不能对类的实例对象
使用插入和提取运算符,而只能对类的指针进行这样的操作。
(4 )集合类
由于所有的集合类都是从 CObject 类派生出来的,而且集合类都包含了与串行化有关的
宏调用,因此就可以通过调用集合类的 Serialize()成员函数,方便地对集合进行串行化 。例如
一个由 CSampleData 对象组成的 CArray 集合,调用 CArray 的 Serialize()函数,就可以使得每
个 CSampleData 对象的 Serialize()函数被依次调用,从而完成对集合类的序列化。
8。1。3 CArchive 类
在前面的章节中已有关于 CArchive 类的介绍,该类提供了一个类型安全的访问 CFile 对
象(CFile 对象是 Visual C++ 中的基本文件对象,将在 8。2 节中详细介绍)的机制,用于将可
串行化对象写入 CFile 对象或者从中读取可串行化对象 。给定的 CArchive 对象可以存储数据,
也可以加载数据,但不允许同时进行,而且其寿命也只限于将对象写入文件或从文件读取对
·180 ·
…………………………………………………………Page 192……………………………………………………………
第 8 章 文件操作
象的一次性传递。这也就是 MFC 中串行化只能顺序进行的原因。
下面介绍 Carchive 类的一些主要功能。
1.构造函数
Carchive 类通过构造函数从已打开的 CFile 对象中创建可以向该 CFile 对象进行串行化的
新对象。其原型为:
CArchive(
CFile* pFile;
UINT nMode;
int nBufSize = 4096;
void* lpBuf = NULL
);
o 参数 pFile 指向需要进行串行化的 CFile 对象。
o 参数 nMode 设置创建对象的标志,如果设置了这个标志,则必须在销毁前调用 Close
函 数 , 否 则 数 据 将 会 损 坏 。 若 取 值 为 CArchive::load : 从 文 件 中 读 取 数 据 ;
CArchive::store :向文件中保存数据;CArchive::bNoFlushOnDelete :防止 CArchive 对
象在被销毁时自动调用 Flush 函数进行更新。
o 参数 nBufSize 设置缓冲区大小。
o 参数 lpBuf 用于自定义缓冲区,取值为 NULL 则由 CArchive 自行处理。
下面是一段示例代码:
CFile file;
file。Open(〃1。dat〃; CFile::modeWrite); //打开 1。dat 文件进行写操作
CArchive archive(&file; CArchive::stroe);; //创建一个对 file 进行数据保存的文档对象
2 .读写函数
(1)插入运算符(》 )
这两个运算符分别用于保存和读取数据,在原型中可以看到 CArchive 类为许多数据类型
进行了重载,这为数据的串行化提供了基础。
(2 )Read()和 Write() 函数
这两个函数分别从文件中读取或写入原始的字节块。原型为:
UINT Read(
void* lpBuf;
UINT nMax
);
void Write(
const void* lpBuf;
UINT nMax
);
o 参数 lpBuf :给出字节块的指针,用于保存数据或者从中读取数据。
·181 ·
…………………………………………………………Page 193……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
o 参数 nMax :用于确定最大的读写字节数。
o Read()函数返回值:返回实际读写的字节数。
(3 )Flush() 函数
该函数用于将缓冲区剩余的数据强制写入文件中。原型为:
void Flush( );
注意该函数只保证数据完全传送到指定的 CFile 对象中,而且必须通过 CFile::Close 才能
完成最终向磁盘写入数据的过程。
3 .状态和标志函数