WTL(Windows Template Library)是一个由微软开发人员创建的库,用于简化Windows应用程序的GUI创建过程。然而,WTL并不包含一些MFC中已有的高级特性,比如序列化支持。为了弥补这一缺陷,开发了CXArchive类,它是一个基于WTL的序列化解决方案,旨在简化WTL和非MFC应用程序中的序列化过程。
CXArchive类基于C++模板,允许开发者创建体积小且运行速度快的应用程序。CXArchive类使用CXFile类来读写文件数据,CXFile是一个对Windows文件API的封装类。CXArchive类实现了缓冲机制以提高性能。下面,将通过实现LONG类型的插入和提取操作符来理解CXArchive类的工作原理。
CXArchive类提供了多种模式,包括存储和加载,以及对缓冲区大小和缓冲区指针的管理。以下是CXArchive类的基本声明:
class CXArchive {
public:
enum Mode { store = 0, load = 1, bNoFlushOnDelete = 2 };
CXArchive(CXFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL);
~CXArchive();
BOOL IsLoading() const;
BOOL IsStoring() const;
CXFile* GetFile() const;
UINT Read(void* lpBuf, UINT nMax);
void Write(const void* lpBuf, UINT nMax);
void Flush();
void Close();
void Abort();
void WriteString(LPCTSTR lpsz);
LPTSTR ReadString(LPTSTR lpsz, UINT nMax) throw(CXArchiveException);
BOOL ReadString(CString& rString);
// 插入操作符
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);
// 提取操作符
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:
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类使用CXFile类指针来绑定文件,并实现缓冲以提高性能。插入操作符检查是否需要刷新内部CXArchive缓冲区,将LONG放入缓冲区并增加缓冲区指针。提取操作符检查是否需要从文件中获取更多数据到内部缓冲区,然后将缓冲区中的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对象,那么在关闭文件后必须删除它。Close将文件指针设置为NULL。
使用CXArchive类序列化对象非常简单。对于基本类型,只需使用插入/提取操作符。对于更复杂的类型,请调用它们的Serialize方法,但不要忘记将CXArchive参数传递给它们。