AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

FMD开发文集 -- CArchive原理

51自学网 2015-08-30 http://www.wanshiok.com

 

五.指定长度数据段落的读写

以下分析
UINT Read(void* lpBuf, UINT nMax); 读取长度为nMax的数据
void Write(const void* lpBuf, UINT nMax); 写入指定长度nMax的数据
对于大段数据的读写,先使用当前缓冲区中的内容或空间读取或写入,若这些空间够用了,则结束。
否则,从剩余的数据中找出最大的缓冲区整数倍大小的一块数据,直接读写到存储煤质(不反复使用缓冲区)。
剩余的余数部分,再使用缓冲区读写。
(说明:缓冲区读写的主要目的是将零散的数据以缓冲区大小为尺度来处理。对于大型数据,其中间的部分,不是零散的数据,使用缓冲区已经没有意思,故直接读写)
①读取

UINT CArchive::Read(void* lpBuf, UINT nMax)
{
ASSERT_VALID(m_pFile);
if (nMax == 0)
return 0;

UINT nMaxTemp = nMax; //还需要读入的长度,读入一部分,就减相应数值,直到此数值变为零

//处理当前缓冲区中剩余部分。
//如果要求读入字节小于缓冲区中剩余部分,则第一部分为要求读入的字节数,
//否则读入全部剩余部分
UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur)); 
memcpy(lpBuf, 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); //要求读入此整数缓冲区部分大小
lpBuf = (BYTE*)lpBuf + nBytes;
nRead += nBytes;
nLeft -= nBytes;
}
while ((nBytes > 0) && (nLeft > 0)); 知道读入了预定大小,或到达文件尾

nMaxTemp -= nRead;

if (nRead == nTemp) //读入的字节等于读入的整数倍部分 该读最后的余数部分了
{
// 建立装有此最后余数部分的内容的CArchive的工作缓冲区。
if (!m_bDirectBuffer)
{
UINT nLeft = max(nMaxTemp, (UINT)m_nBufSize);
UINT nBytes;
BYTE* lpTemp = m_lpBufStart;
nRead = 0;
do
{
nBytes = m_pFile-> Read(lpTemp, nLeft); //从文件中读入到CArchive缓冲区
lpTemp = lpTemp + nBytes;
nRead += nBytes;
nLeft -= nBytes;
}
while ((nBytes > 0) && (nLeft > 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);
ASSERT(nRead == (UINT)(m_lpBufMax - m_lpBufStart));
m_lpBufCur = m_lpBufStart;
}

//读出此剩余部分到输出
nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));
memcpy(lpBuf, m_lpBufCur, nTemp);
m_lpBufCur += nTemp;
nMaxTemp -= nTemp;
}

}
return nMax - nMaxTemp;
}

②保存,写入 void CArchive::Write(const void* lpBuf, UINT nMax)
{
if (nMax == 0)
return;

//读入可能的部分到缓冲区当前的剩余部分
UINT nTemp = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur));
memcpy(m_lpBufCur, lpBuf, nTemp);
m_lpBufCur += nTemp;
lpBuf = (BYTE*)lpBuf + nTemp;
nMax -= nTemp;

if (nMax > 0) //还有未写入的部分
{
Flush();  //将当前缓冲区写入到存储煤质

//计算出整数倍缓冲区大小的字节数
nTemp = nMax - (nMax % m_nBufSize);
m_pFile-> Write(lpBuf, nTemp); //直接写到文件
lpBuf = (BYTE*)lpBuf + nTemp;
nMax -= nTemp;


//剩余部分添加到缓冲区
if (m_bDirectBuffer)
{
// sync up direct mode buffer to new file position
VERIFY(m_pFile-> GetBufferPtr(CFile::bufferWrite, m_nBufSize,
(void**)&m_lpBufStart, (void**)&m_lpBufMax) == (UINT)m_nBufSize);
ASSERT((UINT)m_nBufSize == (UINT)(m_lpBufMax - m_lpBufStart));
m_lpBufCur = m_lpBufStart;
}

// copy remaining to active buffer
ASSERT(nMax < (UINT)m_nBufSize);
ASSERT(m_lpBufCur == m_lpBufStart);
memcpy(m_lpBufCur, lpBuf, nMax);
m_lpBufCur += nMax;
}
}

六.字符串的读写

①CArchive提供的WriteString和ReadString

字符串写 void CArchive::WriteString(LPCTSTR lpsz)
{
ASSERT(AfxIsValidString(lpsz));
Write(lpsz, lstrlen(lpsz) * sizeof(TCHAR)); //调用Write,将字符串对应的一段数据写入
}

字符串读(读取一行字符串) LPTSTR CArchive::ReadString(LPTSTR lpsz, UINT nMax)
{
// if nMax is negative (such a large number doesn''t make sense given today''s
// 2gb address space), then assume it to mean "keep the newline".
int nStop = (int)nMax < 0 ? -(int)nMax : (int)nMax;
ASSERT(AfxIsValidAddress(lpsz, (nStop+1) * sizeof(TCHAR)));

_TUCHAR ch;
int nRead = 0;

TRY
{
while (nRead < nStop)
{
*this >> ch; //读出一个字节

// stop and end-of-line (trailing ''/n'' is ignored) 遇换行—回车
if (ch == ''/n'' || ch == ''/r'')
{
if (ch == ''/r'')
*this >> ch;
// store the newline when called with negative nMax
if ((int)nMax != nStop)
lpsz[nRead++] = ch;
break;
}
lpsz[nRead++] = ch;
}
}
CATCH(CArchiveException, e)
{
if (e-> m_cause == CArchiveException::endOfFile)
{
DELETE_EXCEPTION(e);
if (nRead == 0)
return NULL;
}
else
{
THROW_LAST();
}
}
END_CATCH

lpsz[nRead] = ''/0'';
return lpsz;
}

ReadString到CString对象,可以多行字符 BOOL CArchive::ReadString(CString& rString)
{
rString = &afxChNil;  // empty string without deallocating
const int nMaxSize = 128;
LPTSTR lpsz = rString.GetBuffer(nMaxSize);
LPTSTR lpszResult;
int nLen;
for (;;)
{
lpszResult = ReadString(lpsz, (UINT)-nMaxSize); // store the newline
rString.ReleaseBuffer();

// if string is read completely or EOF
if (lpszResult == NULL ||
(nLen = lstrlen(lpsz)) < nMaxSize ||
lpsz[nLen-1] == ''/n'')
{
break;
}

nLen = rString.GetLength();
lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
}

// remove ''/n'' from end of string if present
lpsz = rString.GetBuffer(0);
nLen = rString.GetLength();
if (nLen != 0 && lpsz[nLen-1] == ''/n'')
rString.GetBufferSetLength(nLen-1);

return lpszResult != NULL;
}

②使用CString对象的"<<"与">>"符读写字符串
CString定义了输入输出符,可以象基本类型的数据一样使用CArchive 的操作符定义

friend CArchive& AFXAPI operator<<(CArchive& ar, const CString& string);
friend CArchive& AFXAPI operator>>(CArchive& ar, CString& string);
// CString serialization code
// String format:
//   UNICODE strings are always prefixed by 0xff, 0xfffe
//   if < 0xff chars: len:BYTE, TCHAR chars
//   if >= 0xff characters: 0xff, len:WORD, TCHAR chars
//   if >= 0xfffe characters: 0xff, 0xffff, len:DWORD, TCHARs

CArchive& AFXAPI operator<<(CArchive& ar, const CString& string)
{
// special signature to recognize unicode strings
#ifdef _UNICODE
ar << (BYTE)0xff;
ar << (WORD)0xfffe;
#endif

if (string.GetData()-> nDataLength < 255)
{
ar << (BYTE)string.GetData()-> nDataLength;
}
else if (string.GetData()-> nDataLength < 0xfffe)
{
ar << (BYTE)0xff;
ar << (WORD)string.GetData()-> nDataLength;
}
else
{
ar << (BYTE)0xff;
ar << (WORD)0xffff;
ar << (DWORD)string.GetData()-> nDataLength;
}
ar.Write(string.m_pchData, string.GetData()-> nDataLength*sizeof(TCHAR));
return ar;
}

// return string length or -1 if UNICODE string is found in the archive
AFX_STATIC UINT AFXAPI _AfxReadStringLength(CArchive& ar)
{
DWORD nNewLen;

// attempt BYTE length first
BYTE bLen;
ar >> bLen;

if (bLen < 0xff)
return bLen;

// attempt WORD length
WORD wLen;
ar >> wLen;
if (wLen == 0xfffe)
{
// UNICODE string prefix (length will follow)
return (UINT)-1;
}
else if (wLen == 0xffff)
{
// read DWORD of length
ar >> nNewLen;
return (UINT)nNewLen;
}
else
return wLen;
}

CArchive& AFXAPI operator>>(CArchive& ar, CString& string)
{
#ifdef _UNICODE
int nConvert = 1;  // if we get ANSI, convert
#else
int nConvert = 0;  // if we get UNICODE, convert
#endif

UINT nNewLen = _AfxReadStringLength(ar);
if (nNewLen == (UINT)-1)
{
nConvert = 1 - nConvert;
nNewLen = _AfxReadStringLength(ar);
ASSERT(nNewLen != -1);
}

// set length of string to new length
UINT nByteLen = nNewLen;
#ifdef _UNICODE
string.GetBufferSetLength((int)nNewLen);
nByteLen += nByteLen * (1 - nConvert); // bytes to read
#else
nByteLen += nByteLen * nConvert;  // bytes to read
if (nNewLen == 0)
string.GetBufferSetLength(0);
else
string.GetBufferSetLength((int)nByteLen+nConvert);
#endif

// read in the characters
if (nNewLen != 0)
{
ASSERT(nByteLen != 0);

// read new data
if (ar.Read(string.m_pchData, nByteLen) != nByteLen)
AfxThrowArchiveException(CArchiveException::endOfFile);

// convert the data if as necessary
if (nConvert != 0)
{
#ifdef _UNICODE
CStringData* pOldData = string.GetData();
LPSTR lpsz = (LPSTR)string.m_pchData;
#else
CStringData* pOldData = string.GetData();
LPWSTR lpsz = (LPWSTR)string.m_pchData;
#endif
lpsz[nNewLen] = ''/0'';  // must be NUL terminated
string.Init();  // don''t delete the old data
string = lpsz;  // convert with operator=(LPWCSTR)
CString::FreeData(pOldData);
}
}
return ar;
}

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。

上一篇:用VC&nbsp;6.0实现串行通信的三种方法  下一篇:解析C语言中的sizeof