• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            一.概述

            CArchive使用了緩沖區(qū),即一段內(nèi)存空間作為臨時(shí)數(shù)據(jù)存儲(chǔ)地,對(duì)CArchive的讀寫都先依次排列到此緩沖區(qū),當(dāng)緩沖區(qū)滿或用戶要求時(shí),將此段整理后的數(shù)據(jù)讀寫到指定的存儲(chǔ)煤質(zhì)。
            當(dāng)建立CArchive對(duì)象時(shí),應(yīng)指定其模式是用于緩沖區(qū)讀,還是用于緩沖區(qū)寫。
            可以這樣理解,CArchive對(duì)象相當(dāng)于鐵路的貨運(yùn)練調(diào)度站,零散的貨物被收集,當(dāng)總量到達(dá)火車運(yùn)量的時(shí)候,由火車裝運(yùn)走。
            當(dāng)接到火車的貨物時(shí),則貨物由被分散到各自的貨主。與貨運(yùn)不同的是,交貨、取貨是按時(shí)間循序執(zhí)行的,而不是憑票據(jù)。因此必須保證送貨的和取貨的貨主按同樣的循序去存或取。
            對(duì)于大型的貨物,則是拆散成火車單位,運(yùn)走,取貨時(shí),依次取各部分,組裝成原物。

            二.內(nèi)部數(shù)據(jù)
            緩沖區(qū)指針 BYTE* m_lpBufStart,指向緩沖區(qū),這個(gè)緩沖區(qū)有可能是底層CFile(如派生類CMemFile)對(duì)象提供的,但一般是CArchive自己建立的。
            緩沖區(qū)尾部指針 BYTE* m_lpBufMax;
            緩沖區(qū)當(dāng)前位置指針 BYTE* m_lpBufCur;
            初始化時(shí),如果是讀模式,當(dāng)前位置在尾部,如果是寫模式,當(dāng)前位置在頭部:

            m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
            三.基本數(shù)據(jù)讀寫

            對(duì)于基本的數(shù)據(jù)類型,例如字節(jié)、雙字等,可以直接使用">>"、"<<"符號(hào)進(jìn)行讀出、寫入。

            //操作符定義捕:
            	
            //插入操作
            CArchive& operator<<(BYTE by);
            CArchive& operator<<(WORD w);
            CArchive& operator<<(LONG l);
            CArchive& operator<<(DWORD dw);
            CArchive& operator<<(float f);
            CArchive& operator<<(double d);
            CArchive& operator<<(int i);
            CArchive& operator<<(short w);
            CArchive& operator<<(char ch);
            CArchive& operator<<(unsigned u);
            
            //提取操作
            CArchive& operator>>(BYTE& by);
            CArchive& operator>>(WORD& w);
            CArchive& operator>>(DWORD& dw);
            CArchive& operator>>(LONG& l);
            CArchive& operator>>(float& f);
            CArchive& operator>>(double& d);
            
            CArchive& operator>>(int& i);
            CArchive& operator>>(short& w);
            CArchive& operator>>(char& ch);
            CArchive& operator>>(unsigned& u);
            下面以雙字為例,分析原碼

            雙字的插入(寫)

            CArchive& CArchive::operator<<(DWORD dw)
            {
            	if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax) //緩沖區(qū)空間不夠
            		Flush();  //緩沖區(qū)內(nèi)容提交到實(shí)際存儲(chǔ)煤質(zhì)。
            
            	if (!(m_nMode & bNoByteSwap))
            		_AfxByteSwap(dw, m_lpBufCur);  //處理字節(jié)順序
            	else
            		*(DWORD*)m_lpBufCur = dw;      //添入緩沖區(qū)
            
            	m_lpBufCur += sizeof(DWORD); 	   //移動(dòng)當(dāng)前指針
            	return *this;
            }
            
            雙字的提取(讀)
            CArchive& CArchive::operator>>(DWORD& dw)
            {
            	if (m_lpBufCur + sizeof(DWORD) > m_lpBufMax) //緩沖區(qū)要讀完了
            		FillBuffer(sizeof(DWORD) - (UINT)(m_lpBufMax - m_lpBufCur));  //重新讀入內(nèi)容到緩沖區(qū)
            
            	dw = *(DWORD*)m_lpBufCur;		//讀取雙字
            	m_lpBufCur += sizeof(DWORD);	//移動(dòng)當(dāng)前位置指針
            
            	if (!(m_nMode & bNoByteSwap))
            		_AfxByteSwap(dw, (BYTE*)&dw);  //處理字節(jié)順序
            	return *this;
            }
            
            四.緩沖區(qū)的更新

            以上操作中,當(dāng)緩沖區(qū)將插入滿或緩沖區(qū)將提取空時(shí),都將對(duì)緩沖區(qū)進(jìn)行更新處理。

            緩沖區(qū)將插入滿時(shí)調(diào)用Flush();
            void CArchive::Flush()
            {
            	ASSERT_VALID(m_pFile);
            	ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
            	ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
            	ASSERT(m_lpBufStart == NULL ||
            		AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, IsStoring()));
            	ASSERT(m_lpBufCur == NULL ||
            		AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, IsStoring()));
            
            	if (IsLoading())
            	{
            		// unget the characters in the buffer, seek back unused amount
            		if (m_lpBufMax != m_lpBufCur)
            			m_pFile-> Seek(-(m_lpBufMax - m_lpBufCur), CFile::current);
            		m_lpBufCur = m_lpBufMax;    // 指向尾
            	}
            	else   //寫模式
            	{
            		if (!m_bDirectBuffer)
            		{
            			// 內(nèi)容寫入到文件
            			if (m_lpBufCur != m_lpBufStart)
            				m_pFile-> Write(m_lpBufStart, m_lpBufCur - m_lpBufStart);
            		}
            		else
            		{
            			//如果是直接針對(duì)內(nèi)存區(qū)域的的(例如CMemFile中) (只需移動(dòng)相關(guān)指針,指向新的一塊內(nèi)存)
            			if (m_lpBufCur != m_lpBufStart)
            				m_pFile-> GetBufferPtr(CFile::bufferCommit, m_lpBufCur - m_lpBufStart);
            			// get next buffer
            			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; //指向緩沖區(qū)首
            	}
            }
            緩沖區(qū)將提取空,會(huì)調(diào)用FillBuffer。 nBytesNeeded為當(dāng)前剩余部分上尚有用的字節(jié)
            void CArchive::FillBuffer(UINT nBytesNeeded)
            {
            	ASSERT_VALID(m_pFile);
            	ASSERT(IsLoading());
            	ASSERT(m_bDirectBuffer || m_lpBufStart != NULL);
            	ASSERT(m_bDirectBuffer || m_lpBufCur != NULL);
            	ASSERT(nBytesNeeded > 0);
            	ASSERT(nBytesNeeded <= (UINT)m_nBufSize);
            	ASSERT(m_lpBufStart == NULL ||
            		AfxIsValidAddress(m_lpBufStart, m_lpBufMax - m_lpBufStart, FALSE));
            	ASSERT(m_lpBufCur == NULL ||
            		AfxIsValidAddress(m_lpBufCur, m_lpBufMax - m_lpBufCur, FALSE));
            
            	UINT nUnused = m_lpBufMax - m_lpBufCur;
            	ULONG nTotalNeeded = ((ULONG)nBytesNeeded) + nUnused;
            
            	// 從文件中讀取
            	if (!m_bDirectBuffer)
            	{
            		ASSERT(m_lpBufCur != NULL);
            		ASSERT(m_lpBufStart != NULL);
            		ASSERT(m_lpBufMax != NULL);
            
            		if (m_lpBufCur > m_lpBufStart)
            		{
            			//保留剩余的尚未處理的部分,將它們移動(dòng)到頭
            			if ((int)nUnused > 0)
            			{
            				memmove(m_lpBufStart, m_lpBufCur, nUnused);
            				m_lpBufCur = m_lpBufStart;
            				m_lpBufMax = m_lpBufStart + nUnused;
            			}
            
            			// read to satisfy nBytesNeeded or nLeft if possible
            			UINT nRead = nUnused;
            			UINT nLeft = m_nBufSize-nUnused;
            			UINT nBytes;
            			BYTE* lpTemp = m_lpBufStart + nUnused;
            			do
            			{
            				nBytes = m_pFile-> Read(lpTemp, nLeft);
            				lpTemp = lpTemp + nBytes;
            				nRead += nBytes;
            				nLeft -= nBytes;
            			}
            			while (nBytes > 0 && nLeft > 0 && nRead < nBytesNeeded);
            
            			m_lpBufCur = m_lpBufStart;
            			m_lpBufMax = m_lpBufStart + nRead;
            		}
            	}
            	else
            	{
            		// 如果是針對(duì)內(nèi)存區(qū)域(CMemFile),移動(dòng)相關(guān)指針,指向新的一塊內(nèi)存
            		if (nUnused != 0)
            			m_pFile-> Seek(-(LONG)nUnused, CFile::current);
            		UINT nActual = m_pFile-> GetBufferPtr(CFile::bufferRead, m_nBufSize,
            			(void**)&m_lpBufStart, (void**)&m_lpBufMax);
            		ASSERT(nActual == (UINT)(m_lpBufMax - m_lpBufStart));
            		m_lpBufCur = m_lpBufStart;
            	}
            
            	// not enough data to fill request?
            	if ((ULONG)(m_lpBufMax - m_lpBufCur) < nTotalNeeded)
            		AfxThrowArchiveException(CArchiveException::endOfFile);
            }
            
            五.指定長度數(shù)據(jù)段落的讀寫

            以下分析
            UINT Read(void* lpBuf, UINT nMax); 讀取長度為nMax的數(shù)據(jù)
            void Write(const void* lpBuf, UINT nMax); 寫入指定長度nMax的數(shù)據(jù)
            對(duì)于大段數(shù)據(jù)的讀寫,先使用當(dāng)前緩沖區(qū)中的內(nèi)容或空間讀取或?qū)懭耄暨@些空間夠用了,則結(jié)束。
            否則,從剩余的數(shù)據(jù)中找出最大的緩沖區(qū)整數(shù)倍大小的一塊數(shù)據(jù),直接讀寫到存儲(chǔ)煤質(zhì)(不反復(fù)使用緩沖區(qū))。
            剩余的余數(shù)部分,再使用緩沖區(qū)讀寫。
            (說明:緩沖區(qū)讀寫的主要目的是將零散的數(shù)據(jù)以緩沖區(qū)大小為尺度來處理。對(duì)于大型數(shù)據(jù),其中間的部分,不是零散的數(shù)據(jù),使用緩沖區(qū)已經(jīng)沒有意思,故直接讀寫)

            ①讀取

            UINT CArchive::Read(void* lpBuf, UINT nMax)
            {
            	ASSERT_VALID(m_pFile);
            	if (nMax == 0)
            		return 0;
            
            	UINT nMaxTemp = nMax;  //還需要讀入的長度,讀入一部分,就減相應(yīng)數(shù)值,直到此數(shù)值變?yōu)榱?
            	
            	//處理當(dāng)前緩沖區(qū)中剩余部分。
            	//如果要求讀入字節(jié)小于緩沖區(qū)中剩余部分,則第一部分為要求讀入的字節(jié)數(shù),
            	//否則讀入全部剩余部分	
            	UINT nTemp = min(nMaxTemp, (UINT)(m_lpBufMax - m_lpBufCur));   
            	memcpy(lpBuf, m_lpBufCur, nTemp);
            	m_lpBufCur += nTemp;
            	lpBuf = (BYTE*)lpBuf + nTemp; //移動(dòng)讀出內(nèi)容所在區(qū)域的指針
            	nMaxTemp -= nTemp;
            
            	//當(dāng)前緩沖區(qū)中剩余部分不夠要求讀入的長度。
            	//還有字節(jié)需要讀,則需要根據(jù)需要執(zhí)行若干次填充緩沖區(qū),讀出,直到讀出指定字節(jié)。
            	if (nMaxTemp != 0)  
            	{
            		//計(jì)算出去除尾數(shù)部分的字節(jié)大小(整數(shù)個(gè)緩沖區(qū)大小) 
            		//對(duì)于這些部分,字節(jié)從文件對(duì)象中讀出,放到輸出緩沖區(qū)
            		nTemp = nMaxTemp - (nMaxTemp % m_nBufSize);  
            		UINT nRead = 0;
            
            		UINT nLeft = nTemp;
            		UINT nBytes;
            		do
            		{
            			nBytes = m_pFile-> Read(lpBuf, nLeft); //要求讀入此整數(shù)緩沖區(qū)部分大小
            			lpBuf = (BYTE*)lpBuf + nBytes;
            			nRead += nBytes;
            			nLeft -= nBytes;
            		}
            		while ((nBytes > 0) && (nLeft > 0)); 知道讀入了預(yù)定大小,或到達(dá)文件尾
            
            		nMaxTemp -= nRead;
            
            		if (nRead == nTemp) //讀入的字節(jié)等于讀入的整數(shù)倍部分  該讀最后的余數(shù)部分了
            		{
            			// 建立裝有此最后余數(shù)部分的內(nèi)容的CArchive的工作緩沖區(qū)。
            			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緩沖區(qū)
            					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;
            	
            	//讀入可能的部分到緩沖區(qū)當(dāng)前的剩余部分	
            	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();    //將當(dāng)前緩沖區(qū)寫入到存儲(chǔ)煤質(zhì)
            
            		//計(jì)算出整數(shù)倍緩沖區(qū)大小的字節(jié)數(shù)
            		nTemp = nMax - (nMax % m_nBufSize);
            		m_pFile-> Write(lpBuf, nTemp);  //直接寫到文件
            		lpBuf = (BYTE*)lpBuf + nTemp;
            		nMax -= nTemp;
            
            
            		//剩余部分添加到緩沖區(qū)
            		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));  //調(diào)用Write,將字符串對(duì)應(yīng)的一段數(shù)據(jù)寫入
            }
            
            字符串讀(讀取一行字符串)
            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;  //讀出一個(gè)字節(jié)
            
            			// 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對(duì)象,可以多行字符
            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對(duì)象的"<<"與">>"符讀寫字符串

            CString定義了輸入輸出符,可以象基本類型的數(shù)據(jù)一樣使用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;
            }
            
            .CObject派生對(duì)象的讀寫

            MFC中多數(shù)類都從CObject類派生,CObject類與CArchive類有著良好的合作關(guān)系,能實(shí)現(xiàn)將對(duì)象序列化儲(chǔ)存到文件或其他媒介中去,或者讀取預(yù)先儲(chǔ)存的對(duì)象,動(dòng)態(tài)建立對(duì)象等功能。

            ①CObject定義了針對(duì)CArvhive的輸入輸出操作符,可以向其他基本數(shù)據(jù)類型一樣使用"<<"、"<<"符號(hào)

            CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)
            	{ ar.WriteObject(pOb); return ar; }
            CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb)
            	{ pOb = ar.ReadObject(NULL); return ar; }
            
            當(dāng)使用這些符號(hào)時(shí),實(shí)際上執(zhí)行的是CArchive的WriteObject和ReadObject成員

            ②WriteObject與ReadObject

            在WriteObject與ReadObject中先寫入或讀取運(yùn)行時(shí)類信息(CRuntimeClas),再調(diào)用Serialze(..),按其中的代碼讀寫具體的對(duì)象數(shù)據(jù)。

            因此,只要在CObject派生類中重載Serilize()函數(shù),寫入具體的讀寫過程,就可以使對(duì)象具有存儲(chǔ)與創(chuàng)建能力。

            //將對(duì)象寫入到緩沖區(qū)
            void CArchive::WriteObject(const CObject* pOb)
            {
            	DWORD nObIndex;
            	// make sure m_pStoreMap is initialized
            	MapObject(NULL);
            
            	if (pOb == NULL)
            	{
            		// save out null tag to represent NULL pointer
            		*this << wNullTag;
            	}
            	else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0)
            		// assumes initialized to 0 map
            	{
            		// save out index of already stored object
            		if (nObIndex < wBigObjectTag)
            			*this << (WORD)nObIndex;
            		else
            		{
            			*this << wBigObjectTag;
            			*this << nObIndex;
            		}
            	}
            	else
            	{
            		// write class of object first
            		CRuntimeClass* pClassRef = pOb-> GetRuntimeClass();
            		WriteClass(pClassRef);  //寫入運(yùn)行類信息
            
            		// enter in stored object table, checking for overflow
            		CheckCount();
            		(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
            
            		// 調(diào)用CObject的Serialize成員,按其中的代碼寫入類中數(shù)據(jù)。
            		((CObject*)pOb)-> Serialize(*this);
            	}
            }
            
            
            CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
            {
            
            	// attempt to load next stream as CRuntimeClass
            	UINT nSchema;
            	DWORD obTag;
            	//先讀入運(yùn)行時(shí)類信息
            	CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);
            
            	// check to see if tag to already loaded object
            	CObject* pOb;
            	if (pClassRef == NULL)
            	{
            		if (obTag > (DWORD)m_pLoadArray-> GetUpperBound())
            		{
            			// tag is too large for the number of objects read so far
            			AfxThrowArchiveException(CArchiveException::badIndex,
            				m_strFileName);
            		}
            
            		pOb = (CObject*)m_pLoadArray-> GetAt(obTag);
            		if (pOb != NULL && pClassRefRequested != NULL &&
            			 !pOb-> IsKindOf(pClassRefRequested))
            		{
            			// loaded an object but of the wrong class
            			AfxThrowArchiveException(CArchiveException::badClass,
            				m_strFileName);
            		}
            	}
            	else
            	{
            		// 建立對(duì)象
            		pOb = pClassRef-> CreateObject();
            		if (pOb == NULL)
            			AfxThrowMemoryException();
            
            		// Add to mapping array BEFORE de-serializing
            		CheckCount();
            		m_pLoadArray-> InsertAt(m_nMapCount++, pOb);
            
            		// Serialize the object with the schema number set in the archive
            		UINT nSchemaSave = m_nObjectSchema;
            		m_nObjectSchema = nSchema;
            		pOb-> Serialize(*this); //調(diào)用CObject的Serialize,按其中代碼讀入對(duì)象數(shù)據(jù)。
            		m_nObjectSchema = nSchemaSave;
            		ASSERT_VALID(pOb);
            	}
            
            	return pOb;
            }
            
            
            ③運(yùn)行時(shí)類信息的讀寫

            為了避免眾多重復(fù)的同類對(duì)象寫入重復(fù)的類信息,CArchive中使用CMap對(duì)象儲(chǔ)存和檢索類信息。

            void CArchive::WriteClass(const CRuntimeClass* pClassRef)
            {
            	ASSERT(pClassRef != NULL);
            	ASSERT(IsStoring());    // proper direction
            
            	if (pClassRef-> m_wSchema == 0xFFFF)
            	{
            		TRACE1("Warning: Cannot call WriteClass/WriteObject for %hs.\n",
            			pClassRef-> m_lpszClassName);
            		AfxThrowNotSupportedException();
            	}
            
            	// make sure m_pStoreMap is initialized
            	MapObject(NULL);
            
            	// write out class id of pOb, with high bit set to indicate
            	// new object follows
            
            	// ASSUME: initialized to 0 map
            	DWORD nClassIndex;
            	if ((nClassIndex = (DWORD)(*m_pStoreMap)[(void*)pClassRef]) != 0)
            	{
            		// previously seen class, write out the index tagged by high bit
            		if (nClassIndex < wBigObjectTag)
            			*this << (WORD)(wClassTag | nClassIndex);
            		else
            		{
            			*this << wBigObjectTag;
            			*this << (dwBigClassTag | nClassIndex);
            		}
            	}
            	else
            	{
            		// store new class
            		*this << wNewClassTag;
            		pClassRef-> Store(*this);
            
            		// store new class reference in map, checking for overflow
            		CheckCount();
            		(*m_pStoreMap)[(void*)pClassRef] = (void*)m_nMapCount++;
            	}
            }
            
            
            CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested,
            	UINT* pSchema, DWORD* pObTag)
            {
            	ASSERT(pClassRefRequested == NULL ||
            		AfxIsValidAddress(pClassRefRequested, sizeof(CRuntimeClass), FALSE));
            	ASSERT(IsLoading());    // proper direction
            
            	if (pClassRefRequested != NULL && pClassRefRequested-> m_wSchema == 0xFFFF)
            	{
            		TRACE1("Warning: Cannot call ReadClass/ReadObject for %hs.\n",
            			pClassRefRequested-> m_lpszClassName);
            		AfxThrowNotSupportedException();
            	}
            
            	// make sure m_pLoadArray is initialized
            	MapObject(NULL);
            
            	// read object tag - if prefixed by wBigObjectTag then DWORD tag follows
            	DWORD obTag;
            	WORD wTag;
            	*this >> wTag;
            	if (wTag == wBigObjectTag)
            		*this >> obTag;
            	else
            		obTag = ((wTag & wClassTag) << 16) | (wTag & ~wClassTag);
            
            	// check for object tag (throw exception if expecting class tag)
            	if (!(obTag & dwBigClassTag))
            	{
            		if (pObTag == NULL)
            			AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);
            
            		*pObTag = obTag;
            		return NULL;
            	}
            
            	CRuntimeClass* pClassRef;
            	UINT nSchema;
            	if (wTag == wNewClassTag)
            	{
            		// new object follows a new class id
            		if ((pClassRef = CRuntimeClass::Load(*this, &nSchema)) == NULL)
            			AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
            
            		// check nSchema against the expected schema
            		if ((pClassRef-> m_wSchema & ~VERSIONABLE_SCHEMA) != nSchema)
            		{
            			if (!(pClassRef-> m_wSchema & VERSIONABLE_SCHEMA))
            			{
            				// schema doesn''t match and not marked as VERSIONABLE_SCHEMA
            				AfxThrowArchiveException(CArchiveException::badSchema,
            					m_strFileName);
            			}
            			else
            			{
            				// they differ -- store the schema for later retrieval
            				if (m_pSchemaMap == NULL)
            					m_pSchemaMap = new CMapPtrToPtr;
            				ASSERT_VALID(m_pSchemaMap);
            				m_pSchemaMap-> SetAt(pClassRef, (void*)nSchema);
            			}
            		}
            		CheckCount();
            		m_pLoadArray-> InsertAt(m_nMapCount++, pClassRef);
            	}
            	else
            	{
            		// existing class index in obTag followed by new object
            		DWORD nClassIndex = (obTag & ~dwBigClassTag);
            		if (nClassIndex == 0 || nClassIndex > (DWORD)m_pLoadArray-> GetUpperBound())
            			AfxThrowArchiveException(CArchiveException::badIndex,
            				m_strFileName);
            
            		pClassRef = (CRuntimeClass*)m_pLoadArray-> GetAt(nClassIndex);
            		ASSERT(pClassRef != NULL);
            
            		// determine schema stored against objects of this type
            		void* pTemp;
            		BOOL bFound = FALSE;
            		nSchema = 0;
            		if (m_pSchemaMap != NULL)
            		{
            			bFound = m_pSchemaMap-> Lookup( pClassRef, pTemp );
            			if (bFound)
            				nSchema = (UINT)pTemp;
            		}
            		if (!bFound)
            			nSchema = pClassRef-> m_wSchema & ~VERSIONABLE_SCHEMA;
               }
            
            	// check for correct derivation
            	if (pClassRefRequested != NULL &&
            		!pClassRef-> IsDerivedFrom(pClassRefRequested))
            	{
            		AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
            	}
            
            	// store nSchema for later examination
            	if (pSchema != NULL)
            		*pSchema = nSchema;
            	else
            		m_nObjectSchema = nSchema;
            
            	// store obTag for later examination
            	if (pObTag != NULL)
            		*pObTag = obTag;
            
            	// return the resulting CRuntimeClass*
            	return pClassRef;
            }
            
            Posted on 2006-09-14 15:17 艾凡赫 閱讀(1156) 評(píng)論(0)  編輯 收藏 引用 所屬分類: MFC技術(shù)C++
            久久精品国产久精国产思思| 人妻少妇精品久久| 亚洲午夜无码AV毛片久久| 精品国产福利久久久| 久久综合久久综合久久综合| 日本欧美久久久久免费播放网| 99精品久久精品一区二区| 久久妇女高潮几次MBA| 久久综合久久自在自线精品自 | 久久久无码精品午夜| 久久丝袜精品中文字幕| 久久青青草原精品国产不卡| 久久综合色区| 久久久久久久精品妇女99| 伊人久久精品无码av一区| 久久精品人成免费| 久久精品国产亚洲沈樵| 亚洲国产成人久久一区久久| 国内高清久久久久久| 99久久精品午夜一区二区| 久久综合久久久| 久久人妻无码中文字幕| 久久久av波多野一区二区| 岛国搬运www久久| 久久久午夜精品| 97精品伊人久久大香线蕉app| 99久久精品久久久久久清纯| 亚洲国产日韩综合久久精品| 精品久久久久久无码专区| 亚洲国产成人精品久久久国产成人一区二区三区综 | 94久久国产乱子伦精品免费| 亚洲欧美久久久久9999 | 欧美久久天天综合香蕉伊| 久久精品国产AV一区二区三区| 国产午夜精品理论片久久影视| 久久久精品日本一区二区三区| 99精品国产综合久久久久五月天| 天天久久狠狠色综合| 日韩乱码人妻无码中文字幕久久 | 精品久久久久久中文字幕大豆网| 精品无码人妻久久久久久|