MFC中有一个非常好用的CMemFile类,可以让我们像读写文件一样来操作一块内存。但是它的最大缺点就是使用了MFC,从CObject继承,这样我们在写非MFC程序时就不能使用这个方便的内存文件类了。下面是我根据MFC的CMemFile的源代码改写的一个CAnsiMemFile类,去掉了CMemFile中使用MFC的部分,希望对大家有用。
CAnsiMemFile的使用非常简单,只用把下面的代码保存到一个AnsiMemFile.h头文件中(这个类没有CPP文件),然后在你的VC工程中#include "AnsiMemFile.h"就可以了。该类的接口和MF的CMemFile类基本一致,可以参考MSDN中CMemFile类的文档。
// AnsiMemFile.h: the CAnsiMemFile class. // // A memory file class without MFC // Version: 1.0 // Data: 2005-10-27 // // //////////////////////////////////////////////////////////////////////
#if !defined(AFX_ANSIMEMFILE_H__2F568214_9834_4B67_B97E_FFB21CDB61F1__INCLUDED_) #define AFX_ANSIMEMFILE_H__2F568214_9834_4B67_B97E_FFB21CDB61F1__INCLUDED_
#include #include #include #include #include
class CAnsiMemFile { protected: UINT m_nGrowBytes; DWORD m_nPosition; DWORD m_nBufferSize; DWORD m_nFileSize; BYTE* m_lpBuffer; BOOL m_bAutoDelete; BYTE* Alloc(DWORD nBytes) { return (BYTE*)malloc((UINT)nBytes); } BYTE* Realloc(BYTE* lpMem, DWORD nBytes) { return (BYTE*)realloc(lpMem, (UINT)nBytes); } #pragma intrinsic(memcpy) BYTE* Memcpy(BYTE* lpMemTarget, const BYTE* lpMemSource, UINT nBytes) { assert(lpMemTarget != NULL); assert(lpMemSource != NULL); //assert(AfxIsValidAddress(lpMemTarget, nBytes)); //assert(AfxIsValidAddress(lpMemSource, nBytes, FALSE)); return (BYTE*)memcpy(lpMemTarget, lpMemSource, nBytes); } #pragma function(memcpy) void Free(BYTE* lpMem) { assert(lpMem != NULL); free(lpMem); } void GrowFile(DWORD dwNewLen) { assert(this); if (dwNewLen > m_nBufferSize) { // grow the buffer DWORD dwNewBufferSize = (DWORD)m_nBufferSize; // watch out for buffers which cannot be grown! assert(m_nGrowBytes != 0); //if (m_nGrowBytes == 0) // AfxThrowMemoryException(); // determine new buffer size while (dwNewBufferSize < dwNewLen) dwNewBufferSize += m_nGrowBytes; // allocate new buffer BYTE* lpNew; if (m_lpBuffer == NULL) lpNew = Alloc(dwNewBufferSize); else lpNew = Realloc(m_lpBuffer, dwNewBufferSize); if (lpNew == NULL) //AfxThrowMemoryException(); throw exception("分配内存错误!"); m_lpBuffer = lpNew; m_nBufferSize = dwNewBufferSize; } assert(this); } public: enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 };
//nGrowBytes 该文件需要增大时的增大粒度(每次增大nGrowBytes个字节) CAnsiMemFile(UINT nGrowBytes = 1024) { assert(nGrowBytes <= UINT_MAX); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; m_lpBuffer = NULL; m_bAutoDelete = TRUE; } //相对于构造后调用Attach CAnsiMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes = 0) { assert(nGrowBytes <= UINT_MAX); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = nBufferSize; m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0; m_lpBuffer = lpBuffer; m_bAutoDelete = FALSE; } ~CAnsiMemFile() { // Close should have already been called, but we check anyway if (m_lpBuffer) Close(); assert(m_lpBuffer == NULL); m_nGrowBytes = 0; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; }
//////////////////////取属性
//取得当前读写位置 DWORD GetPosition() const { assert(this); return m_nPosition; } //取得文件的当前大小 DWORD GetLength() const { DWORD dwLen, dwCur; // Seek is a non const operation CAnsiMemFile* pFile = (CAnsiMemFile*)this; dwCur = pFile->Seek(0L, current); dwLen = pFile->SeekToEnd(); pFile->Seek(dwCur, begin);
return dwLen; } //取得内存数据指针 //注意:只读,不要修改该指针指向的内容。如果需要读写该文件内容,请用Read()和Write() const BYTE const * GetPtr() const { return m_lpBuffer; }
///////////////////////操作 //指定本文件所用的内存 //该对象析构时不会释放改内存块 void Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes) { assert(m_lpBuffer == NULL); m_nGrowBytes = nGrowBytes; m_nPosition = 0; m_nBufferSize = nBufferSize; m_nFileSize = nGrowBytes == 0 ? nBufferSize : 0; m_lpBuffer = lpBuffer; m_bAutoDelete = FALSE; } //解除该文件和它当前占用的内存块的关联 //返回该内存块的指针 BYTE* Detach() { BYTE* lpBuffer = m_lpBuffer; m_lpBuffer = NULL; m_nFileSize = 0; m_nBufferSize = 0; m_nPosition = 0; return lpBuffer; } //移动读写位置到文件最后 DWORD SeekToEnd() { return Seek(0, CAnsiMemFile::end); } //移动读写位置到文件开头 void SeekToBegin() { Seek(0, CAnsiMemFile::begin); } //改变文件长度 //如果需要会重新分配所占内存 void SetLength(DWORD dwNewLen) { assert(this); if (dwNewLen > m_nBufferSize) GrowFile(dwNewLen); if (dwNewLen < m_nPosition) m_nPosition = dwNewLen; m_nFileSize = dwNewLen; assert(this); } //从当前读写位置读取指定长度的数据 UINT Read(void* lpBuf, UINT nCount) { assert(this); if (nCount == 0) return 0; assert(lpBuf != NULL); //assert(AfxIsValidAddress(lpBuf, nCount)); if (m_nPosition > m_nFileSize) return 0; UINT nRead; if (m_nPosition + nCount > m_nFileSize) nRead = (UINT)(m_nFileSize - m_nPosition); else nRead = nCount; Memcpy((BYTE*)lpBuf, (BYTE*)m_lpBuffer + m_nPosition, nRead); m_nPosition += nRead; assert(this); return nRead; } //写指定长度的数据到文件内 void Write(const void* lpBuf, UINT nCount) { assert(this); if (nCount == 0) return; assert(lpBuf != NULL); //assert(AfxIsValidAddress(lpBuf, nCount, FALSE)); if (m_nPosition + nCount > m_nBufferSize) GrowFile(m_nPosition + nCount); assert(m_nPosition + nCount <= m_nBufferSize); Memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount); m_nPosition += nCount; if (m_nPosition > m_nFileSize) m_nFileSize = m_nPosition; assert(this); } //移动读写位置 //lOff 移动的距离 //nFrom 指定从哪里开始移动 // //第二个参数可以为: //enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 }; LONG Seek(LONG lOff, UINT nFrom) { assert(this); assert(nFrom == begin || nFrom == end || nFrom == current); LONG lNewPos = m_nPosition; if (nFrom == begin) lNewPos = lOff; else if (nFrom == current) lNewPos += lOff; else if (nFrom == end) lNewPos = m_nFileSize + lOff; else return -1; if (lNewPos < 0) throw exception("Seek错误"); m_nPosition = lNewPos; assert(this); return m_nPosition; } //关闭内存文件,释放所占用的内存,置长度为0。 //该内存文件不可增长(即不可再写入任何数据) //析构函数会自动调用Close void Close() { assert((m_lpBuffer == NULL && m_nBufferSize == 0) || !m_bAutoDelete || TRUE); assert(m_nFileSize <= m_nBufferSize); m_nGrowBytes = 0; m_nPosition = 0; m_nBufferSize = 0; m_nFileSize = 0; if (m_lpBuffer && m_bAutoDelete) Free(m_lpBuffer); m_lpBuffer = NULL; } }; /////////////////////////////////////////////////////////////////////////////
#endif // !defined(AFX_ANSIMEMFILE_H__2F568214_9834_4B67_B97E_FFB21CDB61F1__INCLUDED_)
下面是一个使用这个类的简单例子(Win32 Console):
// AnsiMemFilePrj.cpp : Defines the entry point for the console application. //
#include "stdafx.h" #include "AnsiMemFile.h"
int main(int argc, char* argv[]) { CAnsiMemFile file; printf("******** BEFORE ********\n"); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("SeekToBegin: \n"); file.SeekToBegin(); printf("SeekToEnb: %d\n", file.SeekToEnd()); printf("Seek 100 from begin: %d\n", file.Seek(100, CAnsiMemFile::begin)); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
char szData[] = "123456789abcde"; printf("Write a string %s to file:\n", szData); file.Write(szData, strlen(szData)); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("Seek to begin:\n"); file.SeekToBegin(); memset(szData, 0, strlen(szData)); printf("Read from file: %d\n |%s|\n", file.Read(szData, 14), szData); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("Seek to end:\n"); file.SeekToEnd(); memset(szData, 0, strlen(szData)); printf("Read from file: %d\n |%s|\n", file.Read(szData, 14), szData); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("Seek to 100 from begin:\n"); file.Seek(100, CAnsiMemFile::begin); memset(szData, 0, strlen(szData)); printf("Try to read 14 bytes from file: %d bytes actually read\n |%s|\n", file.Read(szData, 14), szData); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
//如果添加该代码,则下面的代码会出错 //因为文件关闭后即不能再使用 /*printf("*********** CLOSE ***********\n"); printf("Close() is called...\nAfter close:\n"); file.Close(); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr()); */
printf("SetLength to 5:\n"); file.SetLength(5); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("Seek to begin:\n"); file.SeekToBegin(); printf("Write a string %s (with 0) to file:\n", szData); file.Write(szData, strlen(szData) + 1); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("GetPtr() returns 0x%x. The string is |%s|\n\n", file.GetPtr(), file.GetPtr()); printf("Close() is called...\nAfter close:\n"); file.Close(); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
printf("Seek to 56635 form end\n"); file.Seek(65535, CAnsiMemFile::end); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr());
memset(szData, 0, strlen(szData)); printf("Try to read 14 bytes from file: %d bytes actually read\n |%s|\n", file.Read(szData, 14), szData); printf(">> Length = %d\n", file.GetLength()); printf(">> Position = %d\n", file.GetPosition()); printf(">>Ptr = %x\n\n", file.GetPtr()); return 0; }
| |