MFC第九天

本文介绍MFC中的文件操作方法,包括CFile和CFileFind类的使用,以及如何进行文件的读写和查找。同时深入探讨MFC序列化机制,包括CArchive类的功能与对象序列化的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一  文件操作
  1CFile类,--完成文件的找开和读写操作
  2.CFileFind类--提供了文件查找功能。
       这两个类,父类都是CObject.
  3.CFile类的使用
      2.1找开或者创建文件
          CFile::Open
      2.2数据读写
          CFile::Read/Write注意读写操作的异常捕获
      2.3文件的关闭
          CFile::Close
      2.4文件指针位置
          CFile:Seek/SeekToEnd/SeekToBegin
          Flush--强制将缓冲区数据写入到硬盘
      2.6 LockRange/UnLockRange当多个程序同时操作同一文件时使用
      2.7文件状态信息
         GetStatus/SetStatus
       3.CFileFind类
       3.1 FindFile--开始查找
       3.2 FindNextFile--查找下一个文件(得到第一个文件信息,返回下一个文件是否存在)
       3.3 调用一系列的GetXXX和IsXXX函数获取和判断文件的信息
       3.4 Close结束查找      
 //////////////////////////////
 控制台程序《支持MFC》
 CWinApp theApp;
 void CFileExample(){
 CFile file;
 //打开或者新建文件
 BOOL bRet=file.Open("c:\\mfcfile.txt",CFile::modeCreate|CFile::modeReadWrite);
 if(!bRet) return;
 //文件的读写操作
 try{
 file.Write("Hello CFile",11);
 //移动文件指针到文件的开始位置
 file.SeekToBegin();
 char szText[100]={0};
 file.Read(szText,100);
 printf("%s\n",szText);
 
 }
 catch(CFileException* e){
 //具体的异常处理
 
 }
 //文件关闭
 file.Close();
 }
 ////////////修改文件状态信息
 CFileStatus status;
 CFile::GetStatus("c:\\mfcfile.txt",status);
 CTimeSpan span(366,0,0,0);
 status.m_ctime-=span;
 CFile::SetStatus("c:\\mfcfile.txt",status);
 
 //////////////////////////////             


二 MFC序列化
  1.序列化概念
     采用数据流的方式,将数据依次写入/读取文件,是二进制的存储方式。
  2.序列化相关类
     2.1CFile--文件类
     2.2CArchive--归档类,封装了序列化的操作(完成数据的具体读写操作)
     2.3CObject类(与对象的序列化相关的)
  3.序列化的使用
     3.1  打开或者创建文件
     3.2   定义CArchive对象
     3.3  进行具体的数据读写
            写,存储,  <<
            读,加载,   >>   
      3.4关闭CArchive对象
      3.5关闭文件
   //数据存储
   void Store(){
   CFile file;
   BOOL bRet=file.Open("c:\\serial.dat",CFile::modeCreate|cfile::modeWrite);
   if(!bRet){return;}
   CArchive ar(&file,CArchive::store);//与modeWrite保持一致
   ar<<100;
   float fValue=12.25;
   ar<<fValue;
   CString strValue="Hello CArchive";
   ar<<strValue;
   ar.Close();
   file.Close();
   } 
   //数据读出
   void Load(){
   CFile file;
   file.Open("c:\\serial.dat",CFile::modeRead);
   CArchive ar(&file,CArchive::load);
   int nNum=0;
   ar>>nNum;
   float fNum=0.0;
   ar>>fNum;
   CString strValue;
   ar>>strValue;
   ar.Close();
   file.Close();
   //输入读到的数据
   printf("%d\n",nNum);
   printf("%.xf\n",fNum);
   printf("%s\n",strValue);
   
   }
  
  
  4.CArchive类
    CArchive中定义了缓存,目的减少硬盘的读写次数
    class CArchive{
    CFile* m_pFile;//关联的文件对象
    int m_nBufSize;//缓存的大小
    BYTE* m_lpBufCur;//当前指针位置
    BYTE* m_lpBufMax;//终止指针位置
    BYTE* m_lpBufStart;//起始指针位置
    };
   4.1 数据写入的执行过程(存储)
   4.1.1 判断在Buff中,是否有足够的空间存储数据
   m_lpBufCur+sizeof(数据)>m_lpBufMax
   4.1.2 如果空间不够,首先将Buff中已有的数据写入文件(Flush)
   重置m_lpBufCur到Buff的起始位置
   4.1.3如果空间足够,将数据写入m_lpBufCur执行的地址
   4.1.4将m_lpBufCur向后偏移写入的字节数
   写入到最后,ar.Close()调用Flush
   
   4.2数据读取的执行过程(加载)
   4.2.1 判断在Buff中剩余的空间是否满足读取数据的大小。
   
   
   5.对象的序列化
   序列化对象--将对象的类的信息和对象的数据保存到文件
   反序列化对象--根据读取的类的信息,创建对象,并将对象的数据读取。
   条件:至少是具有运行类信息功能。还具有动态创建对象。
   class CStudent
   {
   CString strName;
   UINT m_nAge;
   } 
  CStudent sta1("张三",18);
  5.1 定义一个支持序列化的类
        5.1.1必须是CObject类的子类
        5.1.2添加序列化的声明宏和实现宏
        5.1.3要重写CObject类函数Serialize
 //////////////////////////////
 //定义支持序列化的类
 class CStudent:public CObject
 {
 public:
 CStudent();
 CStudent(CString name,UINT age);
 void Show();
 //声明宏
 DECLARE_SERIAL(CStudent)
 virtual void Serialize(CArchive& ar);
 public:
 CString m_strName;
 UINT m_nAge;
 }
 //实现宏
 IMPLEMENT_SERIAL(CStudent,CObject,1);
 CStudent::CStudent(){};
 CStudent::CStudent(CString name,UINT age){
 m_strName=name;
 m_nAge=age;
 }
 void CStudent::Show(){
 printf("姓名:%s\n",m_strName);
 printf("年龄:%d\n",m_nAge);
 }
 //重写Serialize函数
 void CStudent::Serialize(CArchive& ar){
 if(ar.IsStoring()){
 ar<<m_strName<<m_nAge;
 }
 else
 {
 arr>>m_strName>>m_nAge;
 }
 
 }
 //实验存储
 void ObjStore(CStudent & stu)
 {
 CFile file;
 file.Open("c:\\stu.dat",CFile::modeCreate|CFile::modeWrite);
 CArchive ar(&file,CArchive::store);
 ar<<&stu;
 ar.Close();
 file.Close();
 }
 //实验加载
 void ObjLoad()
 {
 CFile file;
 file.Open("c:\\stu.dat",CFile::modeRead);
 CArchive ar(&file,CArchive::load);
 CStudent *pStu=NULL;
 ar>>pStu;
 ar.Close();
 file.Close();
 if(pStu){
 pStu->Show();
 }
 }
 
 /////////////////////////////
  5.2宏替换后的代码
  init_CStudent--将CStudent类的运行时类信息的地址保存到应用程序的m_classList链表中
  mperator>>--创建类的对象并读取对象的成员变量数据
  5.3序列化对象的过程
  获取对象的运行时类信息
  将类的名称,版本等信息写入到文件
  调用对象Serialize函数
  在函数中,保存对象的成员变量的数据
  WriteObject->WriteClaps->Store->Serialize
  
  5.4反序列化对象的过程
  从文件中读取类的名称和版本号等信息
  根据读取到的类名称,在m_classList链表中查找该类所对应的运行时类信息
  使用查询到的运行时类信息创建对象
  调用对象的Serialize函数
  在函数中,读取变量的数据
  ReadObject->ReadClass->Load->CreateObject->Serialize
  
  
  
  1 对象的序列化(反序列化)
   
    1.1 对象的序列化的使用
      1.1.1 定义支持序列化的类
      1)是CObject的子孙类
      2)添加支持序列化的宏
        DECLARE_SERIAL
        IMPLEMENT_SERIAL
      3)要重写函数Serialize
        virtual void Serialize( CArchive& ar );
      1.1.2 创建文件
      1.1.3 定义CArchive
      1.1.4 存储对象
      1.1.5 关闭CArchive
      1.1.6 关闭文件
    
    1.2 序列化的实现
      1.2.1 宏代码
      class CAnimal : public CObject
    {
    _DECLARE_DYNCREATE( CAnimal )
AFX_API friend CArchive& AFXAPI 
    operator>>(CArchive& ar, CAnimal * &pOb);
    }
   
    CObject* PASCAL CAnimal::CreateObject()

   return new CAnimal; 

_IMPLEMENT_RUNTIMECLASS( CAnimal, CObject, 0, 
CAnimal::CreateObject )

AFX_CLASSINIT _init_CAnimal( RUNTIME_CLASS(CAnimal) ); 

CArchive& AFXAPI operator>>(CArchive& ar, CAnimal* &pOb)

   pOb = (CAnimal*) 
       ar.ReadObject(RUNTIME_CLASS(CAnimal)); 
return ar; 
}
      
  1.2.2 说明
      
     1)_DECLARE_DYNCREATE 动态创建类
     2)operator>> 读入操作符,读取对象
       数据。不是CAnimal类的成员函数,
       是一个CAnimal类的友员全局函数。
     3) AFX_CLASSINIT _init_CAnimal
       全局变量,在程序启动的时候被创建。
       将CAnimal类RUNTIMECLASS信息
       注册到程序中(保存到数据链表).
       
    1.2.3 执行过程
      
      初始化:
      1) _init_CAnimal变量初始化,在构造
       函数中,将类的CRuntimeClass地址
       保存到程序AFX_MODULE_STATE的
       全局变量中,使用m_classList保存
       这个地址.
      
      写入数据:
      
      2) 使用"<<"写入对象数据,内部调用
       CArchive的WriteObject函数.
      
      3) 在WriteObject函数,将该对象的
       CRuntimeClass信息中的版本号/
       类名称写入到文件.
       
      4) 调用对象的Serialize,保存对象
       内的相关数据.
      
      读取数据:
      5) 使用">>"读取对象数据,实际调用
       的是该类的友员函数
       (即在序列化宏中定义操作符).
      
      6) 在">>"操作符中调用CArchive的
       ReadObject函数读取对象.
       
      7) 在ReadObject中从文件中读取
       版本号和类名称
      
      8) 根据读取的类名称,从m_classList
       中,查找相应的CRuntimeClass的地址
       
      9) 获取到CRuntimeClass地址,使用
        CRuntimeClass的CreateObject函数
        创建该类的对象.
        
      10) 调用对象的Serialize函数,从
        CArchive中读取对象内的数据.
    
    1.3 类的Schema(版本)
      
      1.3.1 通过IMPLEMENT_SERIAL宏
      的第3个参数Schema来控制类的版本
      1.3.2 定义版本时,需要增加
        VERSIONABLE_SCHEMA
      例如: 
        IMPLEMENT_SERIAL( CAnimal, CObject, VERSIONABLE_SCHEMA|1 )
      1.3.3 读取数据时,要增加版本
        判断处理
        CArachive::GetObjectSchema获取
        当前对象的版本号.
      
二 MFC对话框


  1 MFC对话框
    
    1.1 有模式对话框
    1.2 无模式对话框
    
  2 MFC APP对话框的使用
    2.1 对话框窗口
    2.2 应用程序主窗口
 
  3 有模式对话框的使用
    3.1 使用
      3.1.1 定义对话框资源
      3.1.2 定义对话框类
      基于CDialog父类生成子类,将对话框
      的资源ID通过构造函数传递给CDialog
      3.1.3 显示对话框
        int CDialog::DoModal()
      3.1.4 WM_INITDIALOG映射为OnInitDialog
        在这个函数中完成对话框数据的初始化
      3.1.5 消息映射
        使用消息映射宏完成消息处理 
      3.1.6 对话框的关闭
        CDialog::OnOK - 确定的方式关闭,
          DoModal函数返回IDOK
        CDialog::OnCancel - 取消的方式关闭,
          DoModal函数返回IDCANCEL
        CDialog::EndDialog - 关闭并指定
          返回值
    3.2 DoModal执行 
      3.2.1 查找对话框资源
      3.2.2 将父窗口设置成禁止输入状态
      3.2.3 创建对话框窗口
      3.2.4 调用消息循环,等候对话框关闭
         执行3.2.5
      3.2.5 将自己的窗口隐藏
      3.2.6 将父窗口设置激活窗口
      3.2.7 删除对话框窗口
      3.2.8 返回对话框结束参数
      
  4 无模式对话框
    4.1 使用
      4.1.1 定义对话框资源
      4.1.2 定义对话框类
      基于CDialog父类生成子类
      4.1.3 创建对话框
        CDialog::Create创建对话框
      4.1.4 显示对话框
        CDialog::ShowWindow显示
      4.1.5 对话框的关闭
        需要手动添加DestoryWindow函数
        可以在OnOK/OnCancel当中
    4.2 执行
      4.2.1 查找资源
      4.2.2 创建窗口
      
      
    













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值