WTL 的 Archive 类






4.89/5 (31投票s)
MFC CArchive 类的移植,用于简化 WTL 和非 MFC 项目中的序列化
引言
WTL(Windows 模板库)是微软提供的另一个库,我们可以用它来创建 Windows 应用程序。WTL 由几个微软开发人员创建,作为 ATL 的扩展,旨在使 GUI 创建过程更加简单。WTL 基于 C++ 模板,允许开发人员创建体积小且运行速度快的应用程序。但遗憾的是,由于 WTL 未得到微软的支持,并且仅由少数几个程序员开发,它缺少 MFC 中长期存在的一些不错的特性。
其中一个这样的特性是 MFC 中由 CArchive
类提供的序列化支持。为了解决这个问题,我决定将 CArchive
类移植到 WTL,以简化 WTL 和非 MFC 应用程序中的序列化。因此,CXArchive
类诞生了!
CXArchive
声明
class CXArchive { public: // Flag values enum Mode { store = 0, load = 1, bNoFlushOnDelete = 2 }; CXArchive(CXFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL); ~CXArchive(); // These functions access the mode to determine the state // of the CXArchive object BOOL IsLoading() const; BOOL IsStoring() const; CXFile* GetFile() const; // Operations UINT Read(void* lpBuf, UINT nMax); void Write(const void* lpBuf, UINT nMax); void Flush(); void Close(); void Abort(); // close and shutdown without exceptions // Reading and writing strings void WriteString(LPCTSTR lpsz); LPTSTR ReadString(LPTSTR lpsz, UINT nMax) throw(CXArchiveException); BOOL ReadString(CString& rString); // Insertion operations CXArchive& operator<<(BYTE by); CXArchive& operator<<(WORD w); CXArchive& operator<<(LONG l); CXArchive& operator<<(DWORD dw); CXArchive& operator<<(float f); CXArchive& operator<<(double d); CXArchive& operator<<(LONGLONG dwdw); CXArchive& operator<<(ULONGLONG dwdw); CXArchive& operator<<(int i); CXArchive& operator<<(short w); CXArchive& operator<<(char ch); #ifdef _NATIVE_WCHAR_T_DEFINED CXArchive& operator<<(wchar_t ch); #endif CXArchive& operator<<(unsigned u); CXArchive& operator<<(bool b); // Extraction operations CXArchive& operator>>(BYTE& by); CXArchive& operator>>(WORD& w); CXArchive& operator>>(DWORD& dw); CXArchive& operator>>(LONG& l); CXArchive& operator>>(float& f); CXArchive& operator>>(double& d); CXArchive& operator>>(LONGLONG& dwdw); CXArchive& operator>>(ULONGLONG& dwdw); CXArchive& operator>>(int& i); CXArchive& operator>>(short& w); CXArchive& operator>>(char& ch); #ifdef _NATIVE_WCHAR_T_DEFINED CXArchive& operator>>(wchar_t& ch); #endif CXArchive& operator>>(unsigned& u); CXArchive& operator>>(bool& b); protected: // Archive objects can not be copied or assigned CXArchive(const CXArchive& arSrc) {} void operator=(const CXArchive& arSrc) {} void FillBuffer(UINT nBytesNeeded) throw(CXArchiveException); CXFile * m_pFile; string m_strFileName; BOOL m_bDirectBuffer; BOOL m_bBlocking; BOOL m_nMode; BOOL m_bUserBuf; int m_nBufSize; BYTE * m_lpBufCur; BYTE * m_lpBufMax; BYTE * m_lpBufStart; };
CXArchive
描述
在内部,CXArchive
使用 CXFile
类来读写文件中的数据。(CXFile
是我开发的另一个类,它基本上是 Windows 文件 API 的一个包装类。)CXArchive
类与 CXFile
类指针相关联,并实现缓冲以提高性能。为了理解 CXArchive
的工作原理,我们将看看 LONG
的插入和提取运算符的实现。
插入运算符
CXArchive& CXArchive::operator<<(LONGl) { if (m_lpBufCur + sizeof(LONG) > m_lpBufMax) Flush(); *(UNALIGNED LONG*)m_lpBufCur = l; m_lpBufCur += sizeof(LONG); return *this; }
插入运算符检查是否需要刷新内部 CXArchive
缓冲区,将 LONG 放入缓冲区,并递增缓冲区指针。它返回一个 CXArchive
引用,以允许级联插入运算符。
提取运算符
CXArchive& CXArchive::operator>>(LONG&l) { if (m_lpBufCur + sizeof(LONG) > m_lpBufMax) FillBuffer((UINT)(sizeof(LONG) - (m_lpBufMax - m_lpBufCur))); l = *(UNALIGNED LONG*)m_lpBufCur; m_lpBufCur += sizeof(LONG); return *this; }
提取运算符检查是否需要从文件中获取更多数据到内部缓冲区中,然后它将一个 LONG
长度的数据从缓冲区放入 LONG
引用参数中。作为最后一步,它递增缓冲区指针以准备下一次提取。
使用代码
您使用 CXArchive
类的方式与使用 CArchive
类的方式完全相同。在您的类中实现一个 Serialize()
函数,如下所示
void CDriver::Serialize(CXArchive& ar) { if (ar.IsStoring()) { ar << m_byte; ar << m_word; } else { ar >> m_byte; ar >> m_word; } }
然后在您的代码中的某个地方添加以下行。为了序列化您的类
string strFile = "demo.txt"; try { CXFile file1; file1.Open(strFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); CXArchive ar1(&file1, CXArchive::store); CDriver driver1; driver1.Serialize(ar1); ar1.Close(); } catch (CXException& Ex) { MessageBox(NULL, Ex.GetErrorDesc().c_str(), "Archive Demo", MB_OK); }
为了反序列化它
try { CXFile file2; file2.Open(strFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); CXArchive ar2(&file2, CXArchive::load); CDriver driver2; driver2.Serialize(ar2); ar2.Close(); } catch (CXException& Ex) { MessageBox(NULL, Ex.GetErrorDesc().c_str(), "Archive Demo", MB_OK); }
注意:如果您使用 new 在堆上分配 CFile
对象,那么您必须在关闭文件后将其删除。关闭会将文件指针设置为 NULL
。
结论
使用 CXArchive
类序列化您的对象非常容易。对于基本类型,只需使用插入/提取运算符。对于更复杂的类型,调用它们的 Serialize 方法,只需不要忘记将 CXArchive
参数传递给它们。
历史
- 2004年12月1日 - 初始发布。
免责声明
本软件及其附带的文件按“原样”分发,不提供任何形式的保证,无论是明示的还是暗示的。对于可能造成的任何损害,概不负责。用户必须承担使用本软件的全部风险。