420 likes | 643 Views
第 9 章 MFC 的文件处理机制. 9.1 CFile 类 9.2 CArchive 类 9.3 对象的序列化 9.4 宏 DECALRE_SERIAL 和 IMPLEMENT_SERIAL 9.5 MFC 文件命令的默认处理流程. FILE structure. Stores information about current state of stream; used in all stream I/O operations. MFC 的文件处理机制主要有两种: 通过 CFile 类实现文件的读写;
E N D
第9章 MFC的文件处理机制 9.1 CFile类 9.2 CArchive类 9.3 对象的序列化 9.4 宏DECALRE_SERIAL和IMPLEMENT_SERIAL 9.5 MFC文件命令的默认处理流程
FILE structure Stores information about current state of stream; used in all stream I/O operations • MFC的文件处理机制主要有两种: • 通过CFile类实现文件的读写; • 通过对象的序列化(Serialization)实现数据的存储和读写
序列化的基本思想:一个类应该能够对自己的成员变量的数据进行读写操作,对象可以通过读操作而重新创建。由于CObject类提供了保存和加载对象状态的基本功能,所以一般类的对象都具备将状态值写入磁盘或从磁盘中读出的方法,这种对象的保存和恢复的过程称为序列化。 对象成员(派生自CObject) 内存地址 内存 磁盘 文件
9.1 CFile类 CFile类中包含了大量的文件操作函数, 1)用户可以使用CFile类实现文件的read、write、append、delete等操作。 2)相对于其他的文件操作方式,CFile更显得直接和自由。 3) 与C/C++中的文件操作方式接近
9.1 CFile类 1. CFile类常用的成员函数(表9-1) 2. 文件的创建和打开 创建CFile类的对象,并使其与磁盘文件之间建立关系。 CFile的构造函数: CFile::CFile() CFile::CFile(int hFile); CFile::CFile(LPCTSTR lpszFileName, UINT nOpenFlags ); 文件名(字符串常量) 文件打开模式
9.1 CFile类 表9-2 几种常用的文件创建及打开方式
长度=0 例 9-1 长度!=0
9.1 CFile类 偏移字节数 偏移起点位置 3. 文件的读写 读写位置的定位: LONG CFile::Seek(LONG lOff, UINT nFrom); 表 9-3nFrom的取值 void CFile::SeekToBegin() void CFile::SeekToEnd()
9.1 CFile类 待写数据的字节数 待写数据的缓冲区 文件的写操作 void CFile::Write(const void * lpBuf, UINT nCount); 例 9-2
9.1 CFile类 读缓冲区指针 读取的字节数 文件的读操作 UINT CFile::Read(void * lpBuf, UINT nCount);
9.1 CFile类 4. CFile的派生类CMemFile 将一块内存区域当作文件来实现读写操作,便于在程序的独立模块之间交换数据。
9.1 CFile类 5. CFileFind类——查找文件 例 9-7
9.1 CFile类 文件属性的访问
9.2 CArchive类 • 为什么引入CArchive类? • 为了在磁盘文件中保存应用程序类对象,并通过读取在内存中复原它们。 • 如何实现类对象的存储和读写? • -类的序列化(Serialization)机制,自动化的存储机制,保存对象,动态恢复对象。 • - 形如:ar << a << b << … << z; ar >> a >> b >> … >> z;
File App 9.2 CArchive类 Write • 为什么不使用CFile类来实现? • -类的成员比较复杂(访问属性,继承,嵌套其他的类对象),因此存储也变得复杂。 • - 复原这些对象(动态地创建对象)也需要一些机制来实现。 Read
9.2 CArchive类 1. 运算符重载 • 为了便于文件的读写操作,CArhive重载了两个运算符,对基本数据类型和CObject的派生类读写予以支持: • 插入符 << • 提取符 >>
2. 与CFile的关系 包装了CFile
9.2 CArchive类 • BOOL CArchive::IsLoading() • -当CArchive类处于读状态时,返回TRUE • BOOL CArchive::IsStoring() • -当CArchive类处于写状态时,返回TRUE CFile操作完毕,不要忘记调用CFile::Close() 同理,CArchive操作完毕,也要调用CArchive::Close()
9.2 CArchive类 例 9-4
9.3 对象的序列化 1. 序列化的基本概念 序列化(Serialization):是OOP中Object数据的存储和恢复的一种文件读写机制。 对象→字节流,打包 字节流→对象,解包 对象的这种存储技术称为序列化。
写入时,依据嵌套关系依次调用自己的“保存”成员函数,完成数据的写入操作。写入时,依据嵌套关系依次调用自己的“保存”成员函数,完成数据的写入操作。 • 读取时,根据嵌套关系实现自身数据的读取操作。 数据的解包过程 数据的打包过程
9.3 对象的序列化 2. MFC的Serialize函数 virtual void CObject::Serialzie(CArchive& ar); 在标准的MFC应用程序的读写过程中,程序首先调用文档类的序列化函数Serialize()。
9.3 对象的序列化 3. MFC应用程序的序列化过程
9.3 对象的序列化 4. 序列化的顺序 • 对于嵌套对象,必须由外到内调用各个对象的序列化函数; • 写入顺序与读取顺序必须相同。 例 9-5
响应文件菜单的打开与保存命令 本例中的CLetter不能解决动态对象的序列化问题。
9.3 对象的序列化 5. Serialize函数的局限性 • 只能顺序读写文件,不能随机操作文件; • 只能一次性读写文件的所有部分,不能部分读取文件的内容; • 只能操作二进制文件,不能处理文本文件; • 不能操作数据库文件; • 不能共享式操作文件。
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL 序列化的机制,要求可以动态地创建对象,而派生自CObject类的子类不具备动态创建能力,因此需要为其增加动态创建能力。另外,重载>>运算符,用于读取对象创建信息。 为此,MFC采用一对宏: DECLARE_SERIAL & IMPLEMENT_SERIAL DECLARE_SERIAL( class_name ) • Remarks • DECLARE_SERIAL generates the C++ header code necessary for a CObject-derived class that can be serialized. • If DECLARE_SERIAL is included in the class declaration, then IMPLEMENT_SERIAL must be included in the class implementation. • The DECLARE_SERIAL macro includes all the functionality of DECLARE_DYNAMIC and DECLARE_DYNCREATE.
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL DECLARE_SERIAL( class_name ) #define DECLARE_SERIAL(class_name) \DECLARE_DYNCREATE(class_name) \friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL IMPLEMENT_SERIAL( class_name, base_class_name, wSchema) Remarks Generates the C++ code necessary for a dynamic CObject-derived class with run-time access to the class name and position within the hierarchy. #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \ CObject* PASCAL class_name::CreateObject() { return new class_name; } IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, class_name::CreateObject) \ CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) { pOb = (class_name*)ar.ReadObject(RUNTIME_CLASS(class_name)); return ar; }
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL CArchive::ReadObject Reads object data from the archive and constructs an object of the appropriate type.
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL • CONCLUSION: • 从CObject派生,以便重载Serialize() • 在.h文件中使用DECLARE_SERIAL,在.cpp中使用IMPLEMENT_SERIAL • 必须定义一个无参的构造函数,满足对象动态创建的需要 • 因为序列化与Document类紧密相关,且从其Serialize()开始,故程序中的数据应作为Document类的成员。
9.4 宏DECLARE_SERIAL与IMPLEMENT_SERIAL 例 9-6 例 9-6a 文件
9.5 MFC文件命令的默认处理流程 1. 文件打开 菜单命令File->New 菜单命令File->Open OnNewDocument(…) OnOpenDocument(…) GetFile(…) 构造CArchive对象 DeleteContents(…) DeleteContents(…) SetModifiedFlag(FALSE) Serialize(…) SetModifiedFlag(FALSE) 文档对象
9.5 MFC文件命令的默认处理流程 1. 文件打开
9.5 MFC文件命令的默认处理流程 2. 保存文件 菜单命令File->Save 菜单命令File->Save As OnSaveDocument(…) GetFile(…) 构造CArchive对象 DeleteContents(…) Serialize(…) SetModifiedFlag(FALSE) 文件保存完成
9.5 MFC文件命令的默认处理流程 可以重载CDocument类的OnOpenDocument和OnSaveDocument成员函数,从中获取文件名。如 详见例fileDemo