MFC Windows程序设计学习笔记--文件和串行化

文件IO主要为了 支持文档的存储和加载。
多数MFC程序用CArchive对象实现磁盘文档的存储和加载。

1.CFile:

m_hFile 保存着与CFile相关联的文件的句柄。
m_strFileName 文件名称
GetFilePath // 获得完整文件名
GetFileName // 不含路径的文件名
GetFileTitle // 不含路径,不含后缀

CFile file;
CFileException fe;
if(file.Open(_T("File.txt"), CFile::modeReadWrite, &fe))
{
    //
}
else
{
    fe.ReportError();
}
CFile file;
try
{
    file.Open(_T("File.txt"), CFile::modeReadWrite);
    ...
}
catch(CFileException *e)
{
    e->ReportError();
    e->Delete();
}

modeReadWrite
modeRead
modeWrite
modeCreate
modeNoTruncate
shareDenyNone
shareDenyRead
shareDenyWrite
shareDenyExclusive // 禁止其它地方读写

Close// 关闭。CFile析构函数中会自动调用。

BYTE buffer[0x1000];

try
{
    CFile file(_T("File.txt"), CFile::modeRead);
    DWORD dwBytesRemaining = file.GetLength();
    while(dwBytesRemaining)
    {
        DWORD dwPosition = file.GetPosition();
        UINT nBytesRead = file.Read(buffer, sizeof(buffer));
        ::CharLowerBuffer((LPTSTR)buffer, nBytesRead);
        file.Seek(dwPosition, CFile::begin);
        file.Write(buffer, nBytesRead);
        dwBytesRemaining -= nBytesRead;
    }
}
catch(CFileException * fe)
{
    e->ReportError();
    e->Delete();
}

SeekToBegin
SeekToEnd
Rename
Remove
如文件IO中发生错误,Read,Write或其它CFile函数,发出CFileException异常。

2.CStdioFile

CStdioFile派生自CFile,添加了两个成员函数:
ReadString// 读取当前文件位置到下一个回车符间所有数据
WriteString// 写入字符串。字符串内容写入后,额外在其后添加 0x0D和0x0A。
按行读写

对CStdioFile,一行正文由 回车符(0x0D)和换行符(0x0A)定界的字符串。

try
{
    CString string;
    CStdioFile file(_T("File.txt"), CFile::modeRead);
    while(file.ReadString(string))
    {
        ...
    }
}
catch(CFileException *e)
{
    e->ReportError();
    e->Delete();
}

3.文件枚举

::FineFirstFile// 失败返回INVAILD_HANDLE_VALUE
::FineNextFile//成功返回非NULL

typedef struct _WIN32_FIND_DATA {
  DWORD    dwFileAttributes;
  FILETIME ftCreationTime;
  FILETIME ftLastAccessTime;
  FILETIME ftLastWriteTime;
  DWORD    nFileSizeHigh;
  DWORD    nFileSizeLow;
  DWORD    dwReserved0;
  DWORD    dwReserved1;
  TCHAR    cFileName[MAX_PATH];// 完整文件名
  TCHAR    cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;

常用的dwFileAttributes:
FILE_ATTRIBUTE_DIRECTORY 是目录
FILE_ATTRIBUTE_HIDDEN 隐藏的
FILE_ATTRIBUTE_NORMAL 普通的
FILE_ATTRIBUTE_READONLY 只读的
FILE_ATTRIBUTE_TEMPORARY 临时的

文件尺寸:
( nFileSizeHigh * ( MAXDWORD+1)) + nFileSizeLow

void EnumrateFolders()
{
    WIN32_FIND_DATA fd;
    HANDLE hFind = ::FindFirstFile(_T("*.*"), &fd);
    if(hFind != INVALID_HANDLE_VALUE)
    {
        do
        {
            if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                CString name = fd.cFileName;
                if(name != _T(".") && name != _T(".."))
                {
                    ::SetCurrentDirectory(fd.cFileName);
                    EnumerateFolders();
                    ::SetCurrentDirectory(_T(".."));
                }
            }
        }
        while(::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
    }
}

4.串行化和CArchive类

大部分MFC应用用CArchive对象完成读写工作,而CArchive对象转而利用CFile实现文件IO。

4.1.串行化基础
CArchive ar(&file, CArchive::store);
ar << a << b;

CArchive ar(&file, CArchive::Load);
ar >> a >> b;

已具备串行化支持的类

基本数据类型
CString
CTime
CTimeSpan
COleVariant
COleCurrency
COleDataTime
COleDataTimeSpan
CSize
CPoint
CRect
SIZE
POINT
RECT

数据串行化或并行化错误时,MFC会发送一个异常。异常类型取决于错误性质。
CMemoryException
CFileException
CArchiveException

编写可串行化类
a.直接或间接得到CObject的派生类
b.在类声明中写入,DECLARE_SERIAL宏,实现中写入,IMPLEMENT_SERIAL宏。
重载Serialize
c.派生类须有默认构造函数

class CLine : public CObject
{
    DECLARE_SERIAL(CLine)
protected:
    CPoint m_ptFrom;
    CPoint m_ptTo;
    COLORREF m_clrLine;
public:
    CLine(){}
    CLine(CPoint from, CPoint to)
    {
        m_ptFrom = from;
        m_ptTo = to;
    }
    void Serialize(CArchive & ar);
};

IMPLEMENT_SERIAL(CLine, CObject, 2 | VERSIONABLE_SCHEMA)
void CLine::Serialize(CArchive & ar)
{
    CObject::Serialize(ar);
    if(ar.IsStoring())
    {
        ar << m_ptFrom << m_ptTo << m_clrLine;
    }
    else
    {
        UINT nSchema = ar.GetObjectSchema();
        switch(nSchema)
        {
        case 1:
            ar >> m_ptFrom >> m_ptTo;
            m_clrLine = RGB(0, 0, 0);
            break;
        case 2:
            ar >> m_ptFrom >> m_ptTo >> m_clrLine;
            break;
        default:
            AfxThrowArchiveException(CArchiveException::badSchema);
            break;
        }
    }
}

在读回数据时,MFC将档案中记录的模式号和应用程序使用的该类的模式号比较,不匹配时,发送CArchiveException异常。m_cause为CArchive::badSchema。

可视化模式是包含 了 VERSIONABLE_SCHEMA标志的模式号。
此标志存在时,MFC发现版本号不匹配时,不产生CArchiveException异常。

串行化/并行化工作过程

// DWORD举例
CArchive& CArchive::operator<<(DWORD dw)
{
    if(m_lpBufCur + sizeof(DWORD) > m_lpBufMax)
    {
        Flush();
    }

    if(!(m_nMode & bNoByteSwap))
    {
        _AfxByteSwap(dw, m_lpBufCur);
    }
    else
    {
        *(DWORD*)m_lpBufCur = dw;
    }
    m_lpBufCur += sizeof(DWORD);
    return *this;
}

// 举例CString
CArchive& AFXAPI operator<<(CArchive &ar, const CString &string)
{
    if(string.GetData()->nDataLength < 255)
    {
        ar << (BYTE)string.GetData()->nDataLength;
    }

    ar.Write(string.m_pchData, string.GetData()->nDataLength * sizeof(TCHAR));
    return ar;
}

// CObject*
_AFX_INLINE CArchive& AFXAPI operator<<(CArchive & ar, const CObject* pOb)
{
    ar.WriteObject(pOb);// 最终调用对象的Serialize来串行化对象的数据成员
    return ar;
}

CArchive::Write将定量数据复制到档案的内部缓冲区。
MFC处理了UNICODE和ANSI字符的转换,即存入的UNICODE字符可以ANSI形式读出。反之,亦可。

写入档案的首个类对象:
新类标志: 0xFFFF
模式编号:0x????
类名的字符数:0x????
类名:0x????
类的数据成员:

写入档案的非首个类对象:
旧类标志:0x8000// 最高位为1,低15位为类的索引号
类的数据成员:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raindayinrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值