第 40 章
CArchive 类的chā入运算符(<<)和提取运算符(>>)对许多C++固有的数据类型进行了
重载,可以直接使用。例如在上面的程序中要对int 的成员变量m_nType 进行串行化,即可
直接使用chā入运算符和提取运算符。下面列出一些被CArchive 类默认支持的数据类型:
? BYTE:8 位无符号整数。
? WORD:16 位无符号整数。
? LONG:32 位带符号整数。
? DWORD:32 位无符号整数。
? float:单精度浮点数。
? double:双精度浮点数。
? int:32 位带符号整数。
? short:16 位带符号整数。
? char:8 位字符类型。
? unsigned:32 位无符号整数。
(2)CString 和CRect 等类型
CString 和CRect 等类型,虽然不是从CObject 派生的类,但是它们有自己针对CArchive
类的重载chā入运算符和提取运算符,因此也可以直接使用这两个运算符进行串行化。
(3)自定义的类
如果序列化的类中包含其他自定义的内嵌对象,则需要处理后再进行串xìng化。例如在
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_strNcom << m_nType; //保存数据
}
else {
ar >> m_strNcom >> m_nType; //读取数据
}
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·180·
m_Data.Serialize(ar); //串行化m_Data
}
如果CSampleData 类中的CSampleChildData 对象是通过指针在堆中创建的,则代码如下:
public:
CSampleChildData *m_pData;
将CSampleData 类串行化更为简单。首先需要为CSampleChildData 添加串行化代码,即
继承CObject,并添加相应的宏和构造函数,最后编写CSampleChildData 自己的Serialize()
函数。完成对CSampleChildData 的修改后就可以在CSampleData 类的Serialize()函数中用
CArchive 的chā入和提取运算符进行串行化。代码如下:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar.IsStoring()) {
ar << m_strNcom << m_nType << m_pData; //保存数据
}
else {
ar >> m_strNcom >> m_nType >> m_pData; //读取数据
}
}
在上述代码中,之所以能对自定义的类进行chā入和提取运算,是因为在添加的
DECLARE_SERIAL()和IMPLEMENT_SERIAL()宏中包含了对chā入和提取运算符的重载。当
CSampleChildData 对象被写进文件时,这两个宏保证类名和数据一起被写进去;而当从文件
中读入时,类名被读进来,相应的类的对象被动态构造,这些也是由这两个宏包含的代码实
现的。当CSampleChildData 对象被构造后,就可以通过Serialize()自动进行串行化,这是由
于CArchive 的chā入和提取运算符对CObject 类型进行了重载。最后新建的CSampleChildData
对象的指针即保存在m_pData 中。根据上面的分析,对于自定义的类,不能对类的实例对象
使用chā入和提取运算符,而只能对类的指针进行这样的cāo作。
(4)集合类
由于所有的集合类都是从CObject 类派生出来的,而且集合类都包含了与串行化有关的
宏调用,因此就可以通过调用集合类的Serialize()成员函数,方便地对集合进行串行化。例如
一个由CSampleData 对象组成的CArray 集合,调用CArray 的Serialize()函数,就可以使得每
个CSampleData 对象的Serialize()函数被依次调用,从而完成对集合类的序列化。
8.1.3 CArchive 类
在前面的章节中已有关于CArchive 类的介绍,该类提供了一个类型安全的访问CFile 对
象(CFile 对象是Visual C++中的基本文件对象,将在8.2 节中详细介绍)的机制,用于将可
串行化对象写入CFile 对象或者从中读取可串行化对象。给定的CArchive 对象可以存储数据,
也可以加载数据,但不允许同时进行,而且其寿命也只限于将对象写入文件或从文件读取对
枫叶文学网www.fywxw.com
第8 章 文件cāo作
·181·
象的一次xìng传递。这也就是MFC 中串行化只能顺序进行的原因。
下面介绍Carchive 类的一些主要功能。
1.构造函数
Carchive 类通过构造函数从已打开的CFile 对象中创建可以向该CFile 对象进行串行化的
新对象。其原型为:
CArchive(
CFile* pFile,
UINT nMode,
int nBufSize = 4096,
void* lpBuf = NULL
);
? 参数pFile 指向需要进行串行化的CFile 对象。
? 参数nMode 设置创建对象的标志,如果设置了这个标志,则必须在销毁前调用Close
函数, 否则数据将会损坏。若取值为CArchive::load : 从文件中读取数据;
CArchive::store:向文件中保存数据;CArchive::bNoFlushOnDelete:防止CArchive 对
象在被销毁时自动调用Flush 函数进行更新。
? 参数nBufSize 设置缓冲区大小。
? 参数lpBuf 用于自定义缓冲区,取值为NULL 则由CArchive 自行处理。
下面是一段示例代码:
CFile file;
file.Open("1.dat", CFile::modeWrite); //打开1.dat 文件进行写cāo作
CArchive archive(&file, CArchive::stroe);; //创建一个对file 进行数据保存的文档对象
2.读写函数
(1)chā入运算符(<<)和提取运算符(>>)
这两个运算符分别用于保存和读取数据,在原型中可以看到CArchive 类为许多数据类型
进行了重载,这为数据的串行化提供了基础。
(2)Read()和Write()函数
这两个函数分别从文件中读取或写入原始的字节块。原型为:
UINT Read(
void* lpBuf,
UINT nMax
);
void Write(
const void* lpBuf,
UINT nMax
);
? 参数lpBuf:给出字节块的指针,用于保存数据或者从中读取数据。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·182·
? 参数nMax:用于确定最大的读写字节数。
? Read()函数返回值:返回实际读写的字节数。
(3)Flush()函数
该函数用于将缓冲区剩余的数据强制写入文件中。原型为:
void Flush( );
注意该函数只保证数据完全传送到指定的CFile 对象中,而且必须通过CFile::Close 才能
完成最终向磁盘写入数据的过程。
3.状态和标志函数
该类函数主要有IsLoading()和IsStoring()两个函数,这两个函数分别用于确定CArchive
对象是否处于读取状态,或者是否处于保存状态。其原型分别为:
BOOL IsLoading( ) const;
BOOL IsStoring( ) const;
4.Close()函数
该函数用于清空缓冲区,关闭CArchive 对象,并且将CArchive 对象与CFile 对象分离。
其原型为:
void Close( );
8.1.4 加入串行化代码
介绍完串行化的基本内容,本节将讲述如何在文档视图应用程序中添加文档类的串行化
功能的方法来实现文档的保存和读取。
在MFC 中,文档数据进行串行化的处理过程,同样是通过文档类的Serialize()函数进行。
下面以选择“文件|另存为”菜单命令为例介绍这个过程。首先MFC 框架提示用户选取文件
名,并打开对应的CFile 对象。接着框架创建指向该CFile 对象的CArchive 对象。由于是“另
存为”,因此该对象设置为“存储”,即CArchive::store。然后调用CDoccomnt 派生类即程序
的文档类中定义的Serialize()函数,将CArchive 对象的引用传递给该函数。程序的文档类的
Serialize()函数执行完毕后,框架先销毁CArchive 对象,再销毁CFile 对象。
因此,根据上述过程,在文档视图应用程序中进行文档的串行化处理,只需要在文档类
中重载CDoccomnt::Serialize()函数,对特定的文档数据进行串行化即可实现。下面给出一个
在文档类中加入串行化代码的示例代码。该段代码中CSampleDoc 类是程序的文档类,它有
一个CSampleData 类的成员变量指针,用于保存文档数据。示例演示了CSampleDoc 类如何
将CSampleData 类的文档数据串行化。
1.CSampleData 类的声明
具体代码如下:
class CSampleData : public CObject
{
public:
枫叶文学网www.fywxw.com
第8 章 文件cāo作
·183·
//定义的公共数据类型
CString m_strNcom;
int m_nType;
CSampleData();
virtual ~CSampleData();
//定义串行化的宏
DECLARE_SERIAL(CSampleData)
//串行化虚函数
virtual void Serialize(CArchive &ar);
};
2.CSampleData 类的实现
具体代码如下:
//实现串行化的宏
IMPLEMENT_SERIAL(CSampleData, CObject, 0)
//初始化
CSampleData::CSampleData()
{
m_nType=0;
m_strNcom="";
}
CSampleData::~CSampleData()
{
}
//串行化函数
void CSampleData::Serialize(CArchive &ar)
{
//基类的串行化
CObject::Serialize(ar);
if (ar.IsStoring())
{
//存储数据
ar<<m_nType<<m_strNcom;
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·184·
}
else
{
//读取数据
ar>>m_nType>>m_strNcom;
}
}
3.CSampleDoc 类的声明
具体代码如下:
class CSampleDoc : public CDoccomnt
{
protected: // create from serialization only
CSampleDoc();
DECLARE_DYNCREATE(CSampleDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSampleDoc)
public:
virtual BOOL OnNewDoccomnt();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Implcomntation
public:
CSampleData *m_pData; //这里加入自定义文档数据
virtual ~CSampleDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) con
松语文学免费小说阅读_www.16sy.com
重载,可以直接使用。例如在上面的程序中要对int 的成员变量m_nType 进行串行化,即可
直接使用chā入运算符和提取运算符。下面列出一些被CArchive 类默认支持的数据类型:
? BYTE:8 位无符号整数。
? WORD:16 位无符号整数。
? LONG:32 位带符号整数。
? DWORD:32 位无符号整数。
? float:单精度浮点数。
? double:双精度浮点数。
? int:32 位带符号整数。
? short:16 位带符号整数。
? char:8 位字符类型。
? unsigned:32 位无符号整数。
(2)CString 和CRect 等类型
CString 和CRect 等类型,虽然不是从CObject 派生的类,但是它们有自己针对CArchive
类的重载chā入运算符和提取运算符,因此也可以直接使用这两个运算符进行串行化。
(3)自定义的类
如果序列化的类中包含其他自定义的内嵌对象,则需要处理后再进行串xìng化。例如在
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_strNcom << m_nType; //保存数据
}
else {
ar >> m_strNcom >> m_nType; //读取数据
}
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·180·
m_Data.Serialize(ar); //串行化m_Data
}
如果CSampleData 类中的CSampleChildData 对象是通过指针在堆中创建的,则代码如下:
public:
CSampleChildData *m_pData;
将CSampleData 类串行化更为简单。首先需要为CSampleChildData 添加串行化代码,即
继承CObject,并添加相应的宏和构造函数,最后编写CSampleChildData 自己的Serialize()
函数。完成对CSampleChildData 的修改后就可以在CSampleData 类的Serialize()函数中用
CArchive 的chā入和提取运算符进行串行化。代码如下:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar.IsStoring()) {
ar << m_strNcom << m_nType << m_pData; //保存数据
}
else {
ar >> m_strNcom >> m_nType >> m_pData; //读取数据
}
}
在上述代码中,之所以能对自定义的类进行chā入和提取运算,是因为在添加的
DECLARE_SERIAL()和IMPLEMENT_SERIAL()宏中包含了对chā入和提取运算符的重载。当
CSampleChildData 对象被写进文件时,这两个宏保证类名和数据一起被写进去;而当从文件
中读入时,类名被读进来,相应的类的对象被动态构造,这些也是由这两个宏包含的代码实
现的。当CSampleChildData 对象被构造后,就可以通过Serialize()自动进行串行化,这是由
于CArchive 的chā入和提取运算符对CObject 类型进行了重载。最后新建的CSampleChildData
对象的指针即保存在m_pData 中。根据上面的分析,对于自定义的类,不能对类的实例对象
使用chā入和提取运算符,而只能对类的指针进行这样的cāo作。
(4)集合类
由于所有的集合类都是从CObject 类派生出来的,而且集合类都包含了与串行化有关的
宏调用,因此就可以通过调用集合类的Serialize()成员函数,方便地对集合进行串行化。例如
一个由CSampleData 对象组成的CArray 集合,调用CArray 的Serialize()函数,就可以使得每
个CSampleData 对象的Serialize()函数被依次调用,从而完成对集合类的序列化。
8.1.3 CArchive 类
在前面的章节中已有关于CArchive 类的介绍,该类提供了一个类型安全的访问CFile 对
象(CFile 对象是Visual C++中的基本文件对象,将在8.2 节中详细介绍)的机制,用于将可
串行化对象写入CFile 对象或者从中读取可串行化对象。给定的CArchive 对象可以存储数据,
也可以加载数据,但不允许同时进行,而且其寿命也只限于将对象写入文件或从文件读取对
枫叶文学网www.fywxw.com
第8 章 文件cāo作
·181·
象的一次xìng传递。这也就是MFC 中串行化只能顺序进行的原因。
下面介绍Carchive 类的一些主要功能。
1.构造函数
Carchive 类通过构造函数从已打开的CFile 对象中创建可以向该CFile 对象进行串行化的
新对象。其原型为:
CArchive(
CFile* pFile,
UINT nMode,
int nBufSize = 4096,
void* lpBuf = NULL
);
? 参数pFile 指向需要进行串行化的CFile 对象。
? 参数nMode 设置创建对象的标志,如果设置了这个标志,则必须在销毁前调用Close
函数, 否则数据将会损坏。若取值为CArchive::load : 从文件中读取数据;
CArchive::store:向文件中保存数据;CArchive::bNoFlushOnDelete:防止CArchive 对
象在被销毁时自动调用Flush 函数进行更新。
? 参数nBufSize 设置缓冲区大小。
? 参数lpBuf 用于自定义缓冲区,取值为NULL 则由CArchive 自行处理。
下面是一段示例代码:
CFile file;
file.Open("1.dat", CFile::modeWrite); //打开1.dat 文件进行写cāo作
CArchive archive(&file, CArchive::stroe);; //创建一个对file 进行数据保存的文档对象
2.读写函数
(1)chā入运算符(<<)和提取运算符(>>)
这两个运算符分别用于保存和读取数据,在原型中可以看到CArchive 类为许多数据类型
进行了重载,这为数据的串行化提供了基础。
(2)Read()和Write()函数
这两个函数分别从文件中读取或写入原始的字节块。原型为:
UINT Read(
void* lpBuf,
UINT nMax
);
void Write(
const void* lpBuf,
UINT nMax
);
? 参数lpBuf:给出字节块的指针,用于保存数据或者从中读取数据。
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·182·
? 参数nMax:用于确定最大的读写字节数。
? Read()函数返回值:返回实际读写的字节数。
(3)Flush()函数
该函数用于将缓冲区剩余的数据强制写入文件中。原型为:
void Flush( );
注意该函数只保证数据完全传送到指定的CFile 对象中,而且必须通过CFile::Close 才能
完成最终向磁盘写入数据的过程。
3.状态和标志函数
该类函数主要有IsLoading()和IsStoring()两个函数,这两个函数分别用于确定CArchive
对象是否处于读取状态,或者是否处于保存状态。其原型分别为:
BOOL IsLoading( ) const;
BOOL IsStoring( ) const;
4.Close()函数
该函数用于清空缓冲区,关闭CArchive 对象,并且将CArchive 对象与CFile 对象分离。
其原型为:
void Close( );
8.1.4 加入串行化代码
介绍完串行化的基本内容,本节将讲述如何在文档视图应用程序中添加文档类的串行化
功能的方法来实现文档的保存和读取。
在MFC 中,文档数据进行串行化的处理过程,同样是通过文档类的Serialize()函数进行。
下面以选择“文件|另存为”菜单命令为例介绍这个过程。首先MFC 框架提示用户选取文件
名,并打开对应的CFile 对象。接着框架创建指向该CFile 对象的CArchive 对象。由于是“另
存为”,因此该对象设置为“存储”,即CArchive::store。然后调用CDoccomnt 派生类即程序
的文档类中定义的Serialize()函数,将CArchive 对象的引用传递给该函数。程序的文档类的
Serialize()函数执行完毕后,框架先销毁CArchive 对象,再销毁CFile 对象。
因此,根据上述过程,在文档视图应用程序中进行文档的串行化处理,只需要在文档类
中重载CDoccomnt::Serialize()函数,对特定的文档数据进行串行化即可实现。下面给出一个
在文档类中加入串行化代码的示例代码。该段代码中CSampleDoc 类是程序的文档类,它有
一个CSampleData 类的成员变量指针,用于保存文档数据。示例演示了CSampleDoc 类如何
将CSampleData 类的文档数据串行化。
1.CSampleData 类的声明
具体代码如下:
class CSampleData : public CObject
{
public:
枫叶文学网www.fywxw.com
第8 章 文件cāo作
·183·
//定义的公共数据类型
CString m_strNcom;
int m_nType;
CSampleData();
virtual ~CSampleData();
//定义串行化的宏
DECLARE_SERIAL(CSampleData)
//串行化虚函数
virtual void Serialize(CArchive &ar);
};
2.CSampleData 类的实现
具体代码如下:
//实现串行化的宏
IMPLEMENT_SERIAL(CSampleData, CObject, 0)
//初始化
CSampleData::CSampleData()
{
m_nType=0;
m_strNcom="";
}
CSampleData::~CSampleData()
{
}
//串行化函数
void CSampleData::Serialize(CArchive &ar)
{
//基类的串行化
CObject::Serialize(ar);
if (ar.IsStoring())
{
//存储数据
ar<<m_nType<<m_strNcom;
枫叶文学网www.fywxw.com
Visual C++ 6.0 程序设计从入门到精通
·184·
}
else
{
//读取数据
ar>>m_nType>>m_strNcom;
}
}
3.CSampleDoc 类的声明
具体代码如下:
class CSampleDoc : public CDoccomnt
{
protected: // create from serialization only
CSampleDoc();
DECLARE_DYNCREATE(CSampleDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSampleDoc)
public:
virtual BOOL OnNewDoccomnt();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Implcomntation
public:
CSampleData *m_pData; //这里加入自定义文档数据
virtual ~CSampleDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) con
松语文学免费小说阅读_www.16sy.com