程序代码:
#include <afxwin.h> int _tmain(int argc, _TCHAR* argv[]) { CFile file("file.dat", CFile::modeRead); CArchive ar(&file, CArchive::load); SIZE size; ar>>size; return 0; }
首先调用>>的重载函数:
CArchive& operator>>(CArchive& ar, SIZE& size) { ar.EnsureRead(&size, sizeof(SIZE)); return ar; } // 该函数调用CArchive::EnsureRead()来读取缓冲区,是先读取内容,然后判断读取字节数是否与给定字节数相等,如果不相等,则抛出异常。 void CArchive::EnsureRead(void *lpBuf, UINT nCount) { UINT nRead=Read(lpBuf, nCount); if(nRead!=nCount) // 确保读取指定的字节数 { AfxThrowArchiveException(CArchiveException::endOfFile); } }
CArchive::Read()函数负责读取数据,lpBuf为目标缓冲区地址,nCount为待读取字节数。
读取分三部分:
1、 将CArchive当前缓冲区中剩余的内容复制到目标缓冲区,如果不够则继续读取。
2、 如果还需读取的数超出缓冲区容量,则将缓冲区整数倍的数据直接从文件、块设备或直接内存缓冲中读取,留下零头。
3、 读取数据尽可能填满CArchive缓冲区,复制剩余内容到目的缓冲。
UINT CArchive::Read(void* lpBuf, UINT nMax) { if (nMax == 0) return 0; if(lpBuf == NULL) return 0; if(!IsLoading()) // 如果不是并行化,则抛出异常 AfxThrowArchiveException(CArchiveException::writeOnly,m_strFileName); // 首先尝试从当前缓冲区中获取指定长度数据 UINT nMaxTemp = nMax; // 需要读取的字节数 UINT nTemp = min(nMaxTemp, UINT(m_lpBufMax - m_lpBufCur)); Checked::memcpy_s(lpBuf, nMaxTemp, m_lpBufCur, nTemp); // 拷贝到目标缓冲区 m_lpBufCur += nTemp; lpBuf = (BYTE*)lpBuf + nTemp; nMaxTemp -= nTemp; // 还需字节数 if (nMaxTemp != 0) { nTemp = nMaxTemp - (nMaxTemp % m_nBufSize); // 直接从文件或直接缓冲中读取数倍缓冲区的数据。 UINT nRead = 0; // 已读取字节数。 UINT nLeft = nTemp; // 剩余字节数 UINT nBytes; // 本次读取字节数 do { nBytes = m_pFile->Read(lpBuf, nLeft); // 读取nLeft字节 lpBuf = (BYTE*)lpBuf + nBytes; // 修改目的缓冲区指针 nRead += nBytes; nLeft -= nBytes; } while ((nBytes > 0) && (nLeft > 0)); nMaxTemp -= nRead; // 最后一部分数据已经不足一个缓冲区大小。 if (nMaxTemp > 0) { if (nRead == nTemp) { // 先将缓冲区填满,然后再读取。 if (!m_bDirectBuffer) { UINT nLastLeft; // 最后剩余字节数 UINT nLastBytes; if (!m_bBlocking) // 文件设备,尽可能塞满缓冲区。 nLastLeft = max(nMaxTemp, UINT(m_nBufSize)); else // 块设备,需要多少读多少 nLastLeft = nMaxTemp; BYTE* lpTemp = m_lpBufStart; nRead = 0; do { nLastBytes = m_pFile->Read(lpTemp, nLastLeft); lpTemp = lpTemp + nLastBytes; nRead += nLastBytes; nLastLeft -= nLastBytes; } while ((nLastBytes > 0) && (nLastLeft > 0) && nRead < nMaxTemp); m_lpBufCur = m_lpBufStart; // 当前缓冲区指针 m_lpBufMax = m_lpBufStart + nRead; // 最大缓冲区指针 } else { nRead = m_pFile->GetBufferPtr(CFile::bufferRead, m_nBufSize, (void**)&m_lpBufStart, (void**)&m_lpBufMax); m_lpBufCur = m_lpBufStart; } // use first part for rest of read nTemp = min(nMaxTemp, UINT(m_lpBufMax - m_lpBufCur)); Checked::memcpy_s(lpBuf, nMaxTemp, m_lpBufCur, nTemp); m_lpBufCur += nTemp; nMaxTemp -= nTemp; } } } return nMax - nMaxTemp; }