程序代码:
1、CMemFile构造。
m_nPosition是缓冲区当前指针位置,m_nFileSize是缓冲区已提交的大小,m_nPosition可能大于m_nFileSize,但这没有关系,只有m_nFileSize真正反应缓冲区中有多少数据。在下次CMemFile::Write或使用CMemFile::bufferCommit调用CMemFile::GetBufferPtr()时,m_nFileSize将被修改。
2、CArchive构造(代码有删减)。
构造完成的时候,m_ lpBufStart = NULL, m_lpBufMax = NULL, m_lpBufCur = NULL, m_ nBufSize = 4096, m_bDirectBuffer = TRUE.
关于直接缓冲:CMemFile中是一大片缓冲区,比如是0~12040这么大范围。而CArchive看到的只是其中一部分2048~6144这么大范围(6144 – 2048 = m_nBufSize)。CArchive每次直接向它看到的缓冲区写入数据,当写满的时候,就通过CMemFile::bufferCommit参数调用CMemFile::GetBufferPtr()提交缓冲区,CMemFile此时更新文件大小和起始指针。CArchive的当前缓冲区被提交之后,它继续向CMemFile申请一块缓冲区,然后继续写数据。
3、写入数据。
因为此时m_lpBufCur和m_lpBufMax都是NULL,所以执行Flush()。在这个函数中不仅使CMemFile申请了缓冲区,也让CArchive获得了缓冲区界面。
4、第一次执行CArchive::Flush()刷新缓冲区。每次Flush的时候,根据CArchive中的指针更新CMemFile中的位置信息,然后分配更大的内存区。
通过CFile::bufferCommit参数调用CMemFile::GetBufferPtr()提交缓冲区,但其实没有提交任何数据。
然后,第一次通过CFile::bufferWrite参数调用CMemFile::GetBufferPtr()时,CMemFile分配了缓冲区内存,CArchive获得了缓冲区界面。
4、CMemFile::GetBufferPtr()函数。
1、 nCommand有4种可能,定义在CFile中,分别是:bufferRead、bufferWrite、bufferCommit、bufferCheck。
bufferCheck用于获取当前缓冲区是直接缓冲bufferDirect,还是块缓冲bufferBlocking。
bufferCommit用于提交缓冲区,此时nCount用于表明提交字节数。
bufferWrite用于向外界提供一块缓冲区界面。nCount表明外界申请的字节数,ppBufStart返回该缓冲区界面首地址,ppBufMax返回该缓冲区界面最大地址,函数返回值表明缓冲区容量,可能小于nCount。
bufferRead是向外界提供一块数据缓冲区,用于从其中读取数据。ppBufStart用于返回缓冲区界面首地址,ppBufMax用于返回缓冲区界面末地址。
该函数中的GrowFile函数很关键,它负责在缓冲区剩余空间不足时申请缓冲区。
5、1、CMemFile::GrowFile()增长CMemFile文件大小。如果dwNewLen大于当前缓冲区大小,将重新分配内存。如果m_nGrowBytes == 0表明缓冲区不可增长,GrowFile函数会抛出一个内存异常。然后,GrowFile会在当前m_nBufferSize的基础上不断增加m_nGorwBytes,直到大于dwNewLen,这样便计算出来了新缓冲区大小。接下来判断是否已经分配过缓冲区,如果没有则调用Alloc分配缓冲,否则调用ReAlloc在原始缓冲区的基础上分配新缓冲区。