65.9K
CodeProject 正在变化。 阅读更多。
Home

WTL 的 Archive 类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (31投票s)

2004年1月15日

CPOL

2分钟阅读

viewsIcon

99529

downloadIcon

1010

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日 - 初始发布。

免责声明

本软件及其附带的文件按“原样”分发,不提供任何形式的保证,无论是明示的还是暗示的。对于可能造成的任何损害,概不负责。用户必须承担使用本软件的全部风险。

© . All rights reserved.