10.MFC文件操作、对象序列化

一、MFC文件的操作

  1.相关类

    CFile - 文件操作类,封装了关于硬盘文件读写操作的API函数,父类CObject

    CFileFind - 文件查找类,封装了关于文件遍历操作的API函数

  2.CFile类的使用

    2.1文件内容读写

     (1)创建或打开硬盘文件,CFile::Open

     (2)读写文件,CFile::Read / CFile::Write

     (3)设置文件位置,CFile::Seek / CFile::SeekToBegin / CFile::SeekToEnd

     (4)关闭文件,CFile::Close

    2.2文件属性的获取和设置

     (1)CFile::GetStatus

     (2)CFile::SetStatus     

  3.CFileFind类的使用

   (1)利用CFileFind::FindFile函数,开始查找指定目录,如果成功返回TRUE,失败返回FALSE

   (2)利用CFileFind::FindNextFile函数,找到第一个文件,同时通过返回值获取下一个文件是否存在

      存在返回TRUE,不存在返回FALSE

   (3)可以利用一系列CFileFind::GetXXX获取文件信息

   (4)可以利用一系列CFileFind::IsXXX判断文件属性

   (5)结束查找,CFileFind::Close

  相关代码:

#include "stdafx.h"

//文件属性的获取和设置
void FileStatus()
{
    //1 获取文件属性
    CFileStatus status;
    CFile::GetStatus(L"d:\\mfc.txt", status);
    //2 定义一个时间段变量(7天0时0分0秒)
    CTimeSpan span(7, 0, 0, 0);
    //3 基于文件的创建时间提前一周
    status.m_ctime -= span;
    //4 设置文件属性
    CFile::SetStatus(L"d:\\mfc.txt", status);
}

//文件查找操作
void FileFind(CString sPath)
{
    //1 开始查找
    CFileFind find;
    BOOL bRet = find.FindFile(sPath + L"\\*.*");
    while (bRet)
    {
        //2 查找下一个
        bRet = find.FindNextFileW();
        //3 获取文件名称
        //CString sName = find.GetFileName();
        sPath = find.GetFilePath();
        if (!find.IsDots())
        {
            if (find.IsDirectory())
            {
                printf("目录:%S\n", sPath);
                FileFind(sPath);
            }
            else
            {
                printf("文件:%S\n", sPath);
            }
        }
    }
    //结束查找
    find.Close();
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    FileStatus();    
    FileFind(L"D:\\kankan");
    printf("\n");
    return 0;
}
View Code

  运行结果:

  

二、序列化

  1.概念

    将数据以二进制流的方式依次写入到文件或从文件中读取的过程

  2.CArchive类

   2.1 打开或新建文件,CFile::Open

   2.2 读写文件,CFile::Read / CFile::Write

    (1)定义CArchive对象

    (2)具体的数据读写

        <<  写操作 ,>>  读操作

    (3)关闭CArchive对象

   2.3 关闭文件,CFile::Close   

  相关代码: 

#include "stdafx.h"

//写数据(存储)
void Store()
{
    CFile file;
    //1 新建文件
    file.Open(L"d:\\serial.dat", CFile::modeCreate | CFile::modeWrite);
    
    //2 写入数据
    CArchive ar(&file, CArchive::store);//定义CArchive对象
    ar << 100 << 12.34 << 'A';//写数据
    ar.Close();//关闭CArchive对象
    
    //3 关闭文件
    file.Close();
}

//读数据(加载)
void Load()
{
    CFile file;
    file.Open(L"d:\\serial.dat", CFile::modeRead);
    
    CArchive ar(&file, CArchive::load);
    int nValue = 0;
    double fValue = 0.0;
    char cValue;
    ar >> nValue >> fValue >> cValue;
    ar.Close();

    file.Close();
    printf("nValue=%d, fValue=%f, cValue=%c\n", nValue, fValue, cValue);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    Store();
    Load();
    return 0;
}
View Code

  运行结果:

   

三、对象的序列化(第6个机制,MFC其余5大机制:程序启动、窗口创建、消息映射、动态创建、运行时类信息)

  1.概念

   序列化对象 - 将对象的类的信息和对象的成员变量以二进制流的方式依次写入到文件的过程。         

   反序列化对象 - 首先读取类的信息,创建对象,然后读取文件中的成员变量赋值给对象的过程。

 2.使用

  2.1 定义支持序列化的类 ★

   (1)派生自CObject类

   (2)在类的内部添加序列化声明宏 DECLARE_SERIAL

      在类的外部添加序列化的实现宏 IMPLEMENT_SERIAL

   (3)重写virtual void Serialize( CArchive & ar )函数,在函数中完成类的成员变量的序列化

  相关代码:

#include "stdafx.h"

//1 定义支持序列化的类
class CStudent : public CObject
{
    //DECLARE_SERIAL(CStudent)  //序列化声明宏
/***********************************************************************************/
    _DECLARE_DYNCREATE(CStudent)
    AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CStudent* &pOb);
/***********************************************************************************/
public:
    CStudent(){ }
    CStudent(CString sName, int nAge) : m_sName(sName), m_nAge(nAge) { }
    void Show() 
    { 
        printf("姓名:%S,年龄:%d\n", m_sName, m_nAge);
    }
    virtual void Serialize(CArchive& ar)
    {
        CObject::Serialize(ar); // 如果父类有需要序列化,调用父类的函数
        if (ar.IsStoring())
            ar << m_sName << m_nAge;
        else
            ar >> m_sName >> m_nAge;
    }
private:
    CString m_sName;
    int m_nAge;
};
//序列化的实现宏
//IMPLEMENT_SERIAL(CStudent, CObject, 1)
/***********************************************************************************/
CObject* PASCAL CStudent::CreateObject()
{
    return new CStudent;
}

extern AFX_CLASSINIT _init_CStudent;

_IMPLEMENT_RUNTIMECLASS(CStudent, CObject, 1, CStudent::CreateObject, &_init_CStudent)

AFX_CLASSINIT _init_CStudent(RUNTIME_CLASS(CStudent));

CArchive& AFXAPI operator>>(CArchive& ar, CStudent* &pOb)
{
    pOb = (CStudent*)ar.ReadObject(RUNTIME_CLASS(CStudent));
    return ar;
}
/***********************************************************************************/

//2 写对象(序列化)
void ObjectStore(CStudent *pStu)
{
    CFile file;
    file.Open(L"d:\\stu.bin", CFile::modeCreate | CFile::modeWrite);
    CArchive ar(&file, CArchive::store);
    ar << pStu;
    ar.Close();
    file.Close();
}

//3 读对象(反序列化)
void ObjectLoad()
{
    CFile file;
    file.Open(L"d:\\stu.bin", CFile::modeRead);
    CArchive ar(&file, CArchive::load);
    CStudent *pStu = NULL;
    ar >> pStu;
    ar.Close();
    file.Close();
    if (pStu)
    {
        pStu->Show();
        delete pStu;
        pStu = NULL;
    }
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CStudent student(L"mike", 30);
    ObjectStore(&student);
    ObjectLoad();
    return 0;
}
View Code

  运行结果:

  

  2.2 使用

    读写时,与基本类型的数据一样方便,但是,参数是对象的地址

  2.3 实现原理

   (1)展开宏

   (2)成员

      _init_CStudent,全局的变量,类型是AFX_CLASSINIT

      operator>>,全局函数,作用是读取对象

   (3)结构的说明   

      struct  AFX_CLASSINIT
      {

        AFX_CLASSINIT( CRuntimeClass*  pNewClass )

        {

          AfxClassInit( pNewClass )

          {

            //将classCStudent的地址保存到应用程序的链表m_classList中

            pModuleState->m_classList.AddHead( pNewClass );

          }

        }

      };  

   (4)写对象的过程    

      _AFX_INLINE  CArchive&  AFXAPI  operator<<( CArchive&  ar,  const  CObject*  pOb )
      {

        ar.WriteObject( pOb )

        {     

          //获取classCStudent变量

          CRuntimeClass*  pClassRef  =  pOb->GetRuntimeClass( );  

          //将类信息写入到文件

          WriteClass( pClassRef )  

          {         

            *this  <<  wNewClassTag;

            pClassRef->Store( *this )  //将类的版本、类名称长度、类名称依次写入到文件

            {           

              WORD nLen  =  ( WORD )AtlStrLen( m_lpszClassName ); 

              ar  <<  ( WORD )m_wSchema  <<  nLen;  

              ar.Write( m_lpszClassName,  nLen*sizeof( char ) );

            }

          }

          //根据多态的特性,将成员变量依次写入到文件

          ( ( CObject* )pOb )->Serialize( *this )   //this为ar的地址

          {

            CObject::Serialize( ar ); 

            if ( ar.IsStoring( ) )

              ar << m_sName << m_nAge;

            else

              ar >> m_sName >> m_nAge;

          }

        }

         return ar;

      }

   (5)读对象过程  

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

      {
        pOb  =  ( CStudent* )ar.ReadObject( RUNTIME_CLASS( CStudent ) )

        {         

          UINT  nSchema;

          DWORD  obTag;

          //读取类的信息

          CRuntimeClass*  pClassRef  =  ReadClass( RUNTIME_CLASS( CStudent ),  &nSchema,  &obTag )

          {

            pClassRef  =  CRuntimeClass::Load( *this,  &nSchema ) )  //this为ar的地址

            {    

              //依次读取类的版本、类名长度、类名         

              WORD  nLen;

              char  szClassName[ 64 ];

              ar  >>  wTemp;  

              ar  >>  nLen;

              ar.Read( szClassName,  nLen*sizeof( char ) )

              //根据类的名称查找并返回对应的classCStudent运行时类信息

              CRuntimeClass*  pClass =  FromName( szClassName );  

              return  pClass;

            }

            return  pClassRef;

          }

        }

        pOb->Serialize( *this )     

        {        

          CObject::Serialize( ar );

          if  ( ar.IsStoring( ) )

            ar  <<  m_sName  <<  m_nAge;

          else

            ar  >>  m_sName  >>  m_nAge;

        }

        return  ar;
      }

 例子:1.自定义一个地址类型,支持序列化,能够序列化该类的对象

      class  CAddress

      {

        CString  m_sProvince;

        CString  m_sCity;

      };

    2.修改CStudent类,增加CAddress类型的成员变量,能够序列化该类的对象

  相关代码:

#include "stdafx.h"


class CAddress : public CObject
{
    DECLARE_SERIAL(CAddress)
public:
    CAddress(){}
    CAddress(CString sProvince, CString sCity)
    {
        m_sProvince = sProvince;
        m_sCity = sCity;
    }
    CAddress(CAddress const& addr)
    {
        m_sProvince = addr.m_sProvince;
        m_sCity = addr.m_sCity;
    }
    void Show()
    {
        printf("地址:%S省%S市", m_sProvince, m_sCity);
    }
    virtual void Serialize(CArchive& ar)
    {
        CObject::Serialize(ar);
        if (ar.IsStoring())
            ar << m_sProvince << m_sCity;
        else
            ar >> m_sProvince >> m_sCity;
    }
private:
    CString m_sProvince;
    CString m_sCity;
};
IMPLEMENT_SERIAL(CAddress, CObject, 1)


class CStudent : public CObject
{
    DECLARE_SERIAL(CStudent)
public:
    CStudent(){ }
    CStudent(CString sName, int nAge)
        : m_sName(sName), m_nAge(nAge) 
    { 
    }
    CStudent(CString sName, int nAge, CAddress sAddress)
        : m_sName(sName), m_nAge(nAge), m_address(sAddress) 
    { 
    }
    void Show()
    {
        printf("姓名:%S,年龄:%d\n", m_sName, m_nAge);
        m_address.Show();
    }
    virtual void Serialize(CArchive& ar)
    {
        CObject::Serialize(ar); 
        m_address.Serialize(ar);
        if (ar.IsStoring())
            ar << m_sName << m_nAge;
        else
            ar >> m_sName >> m_nAge;
    }
private:
    CString  m_sName;
    int      m_nAge;    
    CAddress m_address;
};
IMPLEMENT_SERIAL(CStudent, CObject, 1)


void ObjectStore(CStudent *pStu)
{
    CFile file;
    file.Open(L"d:\\stu2.bin", CFile::modeCreate | CFile::modeWrite);
    CArchive ar(&file, CArchive::store);
    ar << pStu;
    ar.Close();
    file.Close();
}

void ObjectLoad()
{
    CFile file;
    file.Open(L"d:\\stu2.bin", CFile::modeRead);
    CArchive ar(&file, CArchive::load);
    CStudent *pStu = NULL;
    ar >> pStu;
    ar.Close();
    file.Close();
    if (pStu)
    {
        pStu->Show();
        delete pStu;
        pStu = NULL;
    }
}


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CAddress address(L"Sichuan", L"Chengdu");
    CStudent student(L"Mike", 30, address);
    ObjectStore(&student);
    ObjectLoad();
    printf("\n");
    return 0;
}
View Code

  相关结果:

  

posted @ 2016-07-26 11:06  甩锅侠  阅读(582)  评论(0)    收藏  举报