您的位置:首页 > 其它

程序调试--基本数据类型向CFile的串行化

2011-04-07 17:48 381 查看
程序代码:

#include <afxwin.h>
int _tmain(int argc, _TCHAR* argv[])
{
CFile file(_T("file.dat"), CFile::modeReadWrite | CFile::modeCreate);
CArchive ar(&file, CArchive::store);
LONG a = 10, b = 20;
ar<<a<<b;
return 0;
}


程序执行流程:

1、CArchive构造,pFile为指向file的指针(一定不能为NULL),nMode为CArchive::store,nBufSize取了默认值为4096,lpBuf取了默认值为NULL。

CArchive::CArchive(CFile* pFile, UINT nMode, int nBufSize, void* lpBuf)
{
// initialize members not dependent on allocated buffer
m_nMode = nMode;			// 操作模式
m_pFile = pFile;			// 文件指针
// initialize the buffer.  minimum size is 128
m_lpBufStart = (BYTE*)lpBuf;	// 缓冲区起始地址
m_bUserBuf = TRUE;				// 是否是用户指定缓冲区,为FALSE表明CArchive自己管理缓冲区。
m_bDirectBuffer = FALSE;			// 是否是直接缓冲
// 调整缓冲区大小
if (nBufSize < nBufSizeMin)		// nBufSizeMin 为 128
{
// force use of private buffer of minimum size
m_nBufSize = nBufSizeMin;
m_lpBufStart = NULL;
}
else
m_nBufSize = nBufSize;
nBufSize = m_nBufSize;
if (m_lpBufStart == NULL)
{
// check for CFile providing buffering support
// CFile::GetBufferPtr只是简单的返回0,所以m_bDirectBuffer = FALSE
m_bDirectBuffer = m_pFile->GetBufferPtr(CFile::bufferCheck)&CFile::bufferDirect;
if (!m_bDirectBuffer)
{
// no support for direct buffering, allocate new buffer
m_lpBufStart = new BYTE[m_nBufSize];	// 分配缓冲区
m_bUserBuf = FALSE;
}
else
{
// CFile* supports direct buffering!
nBufSize = 0;   // will trigger initial FillBuffer
}
}
m_lpBufMax = m_lpBufStart + nBufSize;		// 缓冲区最大地址
m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;		// 更新缓冲区当前地址
}


在初始化的时候,m_lpBufStart、m_lpBufMax、m_lpBufCur、m_nBufSize、m_bDirectBuffer这几个成员变量比较重要。m_lpBufStart是缓冲区起始地址,m_lpBufMax是缓冲区最大地址,m_lpBufCur是缓冲区当前地址,m_nBufSize是缓冲区大小,m_bDirectBuffer表明是否是直接缓冲(如CMemFile,直接存到内存中,不写入文件)。m_lpBufCur在读取数据的时候是指向m_lpBufMax,因为在开始读取时,m_lpBufCur == m_lpBufMax表明当前缓冲区已经读取完成,将会加载新的缓冲区,这样程序就从file中读取数据来填充缓冲区。

2、串行化长整型值。
CArchive& CArchive::operator<<(LONG l)
{
if(!IsStoring())		AfxThrowArchiveException(CArchiveException::readOnly,m_strFileName);
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax) Flush();	// 缓冲区剩余容量不够,将缓冲区数据刷新到文件
*(UNALIGNED LONG*)m_lpBufCur = l; m_lpBufCur += sizeof(LONG); return *this;
}

这个函数是CArchive的成员函数,在afx.inl中定义。它先检查当前缓冲区是否还能容下待写入数据。如果空间不足,先调用CArchive::Flush()函数,将缓冲区数据写入到文件中。然后,将m_lpBufCur指针转换为BYTE*,直接写入数据。
CArchive::Flush()函数过程如下:
void CArchive::Flush()
{
if (!m_bDirectBuffer)		// FALSE
{
// write out the current buffer to file
if (m_lpBufCur != m_lpBufStart)		// 写入到文件中
m_pFile->Write(m_lpBufStart, ULONG(m_lpBufCur - m_lpBufStart));
}
else
{
// commit current buffer
if (m_lpBufCur != m_lpBufStart)
m_pFile->GetBufferPtr(CFile::bufferCommit, ULONG(m_lpBufCur - m_lpBufStart));
// get next buffer
VERIFY(m_pFile->GetBufferPtr(CFile::bufferWrite, m_nBufSize,
(void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
}
m_lpBufCur = m_lpBufStart;
}

因为m_bDirectBuffer为FALSE,所以调用第一个if子句。检测当前缓冲区指针是否不等于缓冲区起始指针,如果不等则表明缓冲区中有数据,进而调用CFile::Write()将缓冲区数据写入到文件中。

3、CArchive析构。
显然,如果缓冲区中还有数据,CArchive直接析构将导致数据丢失,所以应该在析构时再刷新一次缓冲区。
CArchive::~CArchive()
{
// Close makes m_pFile NULL. If it is not NULL, we must Close the CArchive
if (m_pFile != NULL && !(m_nMode & bNoFlushOnDelete))
Close();		// 将当前缓冲区数据保存到文件中
Abort();    // 执行其他清理工作
}
void CArchive::Close()
{
Flush();
m_pFile = NULL;
}


一点额外的东西。

从CArchive的构造函数可以看出CArchive允许用户自己定义缓冲区,而非由CArchive自己来管理缓冲区。同时,要使用用户自定义缓冲区,该缓冲区大小应该大于128字节。见如下示例代码:

#include <afxwin.h>
int _tmain(int argc, _TCHAR* argv[])
{
CFile file(_T("file.dat"), CFile::modeReadWrite | CFile::modeCreate);
BYTE* pBuffer = new BYTE[512];
CArchive ar(&file, CArchive::store, 512, pBuffer);
LONG a = 10, b = 20;
ar<<a<<b;
return 0;
}


通过调试可以发现,CArchive将数据写入到了pBuffer所指的内存区中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: