• 代码设计:C++ 一个序列化Archive类


            序列化是一个常见的功能,与数据库、配置文件不同,序列化一般是以二进制方式存储的,不考虑肉眼可读性。

            序列化的基本原理很简单,用同样的顺序写入写出即可。主要需要琢磨的是如何用尽可能简洁的方式来实现,客户代码需要添加的部分越少越好。

            这是我写过的一个版本(测试代码也在里面):

    1. //Archive.h 二进制序列化
    2. #ifndef STD_ARCHIVE_H
    3. #define STD_ARCHIVE_H
    4. namespace ns__std_2
    5. {
    6. class CArchive
    7. {
    8. public:
    9. CBuffer m_buf;
    10. void StartArchive(char const * name)
    11. {
    12. m_buf.setSize(0);
    13. m_buf.AddData((void *)name,strlen(name)+1);
    14. }
    15. //对各种类型的操作
    16. template<typename T>
    17. CArchive & operator<<(T const & data)
    18. {
    19. data.Serialize(*this);
    20. return *this;
    21. }
    22. template<typename T>
    23. CArchive & Add(T const & data)
    24. {
    25. m_buf.AddData(&data,sizeof(T));
    26. return *this;
    27. }
    28. //对基本类型的特化,如果用到其它基本类型会导致“Serialize不支持”错误,需要在此增加
    29. template <long BUFSIZE >
    30. CArchive & operator<<(sstring const & data) { m_buf.AddData(data.c_str(), data.size() + 1); return *this; }
    31. CArchive & operator<<(char const * data) { m_buf.AddData(data, strlen(data) + 1); return *this; }
    32. CArchive & operator<<(char * data) { m_buf.AddData(data, strlen(data) + 1); return *this; }
    33. CArchive & operator<<(string const & data){ m_buf.AddData((void *)data.c_str(), data.size() + 1); return *this; }
    34. CArchive & operator<<(long data) { return Add(data); }
    35. CArchive & operator<<(int data) { return Add(data); }
    36. CArchive & operator<<(unsigned long data) { return Add(data); }
    37. CArchive & operator<<(unsigned int data) { return Add(data); }
    38. CArchive & operator<<(bool data) { return Add(data); }
    39. };
    40. class CUnArchive
    41. {
    42. private:
    43. CBuffer const * m_pBuf;
    44. string::size_type m_pos;
    45. bool m_isOK;
    46. public:
    47. operator bool ()const{return m_isOK;}
    48. long getPos()const { return m_pos; }
    49. bool StartUnArchive(char const * name, CBuffer const * source)
    50. {
    51. m_pBuf=source;
    52. m_pos=0;
    53. m_isOK=true;
    54. if(0!=strcmp(name,m_pBuf->data()))
    55. {
    56. m_isOK=false;
    57. }
    58. m_pos+=strlen(m_pBuf->data())+1;
    59. return operator bool ();
    60. }
    61. //对各种类型的操作
    62. template<typename T>
    63. CUnArchive & operator>>(T & data)
    64. {
    65. if (!m_isOK)return *this;
    66. data.UnSerialize(*this);
    67. return *this;
    68. }
    69. template<typename T>
    70. CUnArchive & Get(T & data)
    71. {
    72. if (m_pos >= m_pBuf->size())
    73. {
    74. thelog << "溢出 " << m_pBuf->size() << " " << m_pos << ende;
    75. m_isOK = false;
    76. return *this;
    77. }
    78. memcpy(&data, m_pBuf->data() + m_pos, sizeof(T));
    79. m_pos += sizeof(T);
    80. return *this;
    81. }
    82. //对基本类型的特化,如果用到其它基本类型会导致“UnSerialize不支持”错误,需要在此增加
    83. template <long BUFSIZE >
    84. CUnArchive & operator>>(sstring & data)
    85. {
    86. if (m_pos >= m_pBuf->size())
    87. {
    88. thelog << "溢出 " << m_pBuf->size() << " " << m_pos << ende;
    89. m_isOK = false;
    90. return *this;
    91. }
    92. data = m_pBuf->data() + m_pos;
    93. m_pos += strlen(m_pBuf->data() + m_pos) + 1;//必须用原始数据计算长度
    94. return *this;
    95. }
    96. CUnArchive & operator>>(string & data)
    97. {
    98. if (m_pos >= m_pBuf->size())
    99. {
    100. thelog << "溢出 " << m_pBuf->size() << " " << m_pos << ende;
    101. m_isOK = false;
    102. return *this;
    103. }
    104. data = m_pBuf->data() + m_pos;
    105. m_pos += strlen(m_pBuf->data() + m_pos) + 1;//必须用原始数据计算长度
    106. return *this;
    107. }
    108. CUnArchive & operator>>(long & data) { return Get(data); }
    109. CUnArchive & operator>>(int & data) { return Get(data); }
    110. CUnArchive & operator>>(unsigned long & data) { return Get(data); }
    111. CUnArchive & operator>>(unsigned int & data) { return Get(data); }
    112. CUnArchive & operator>>(bool & data) { return Get(data); }
    113. };
    114. class CArchiveTest
    115. {
    116. public:
    117. struct A
    118. {
    119. bool a;
    120. int b;
    121. long c;
    122. string d;
    123. sstring<16> f;
    124. void Serialize(CArchive & ar)const
    125. {
    126. ar << a << b << c << d << f;
    127. }
    128. void UnSerialize(CUnArchive & unar)
    129. {
    130. unar >> a >> b >> c >> d >> f;
    131. }
    132. };
    133. static int CArchiveTest_doTest(int argc,char ** argv)
    134. {
    135. CArchive ar;
    136. A tmp;
    137. tmp.a=true;
    138. tmp.b=1;
    139. tmp.c=2;
    140. tmp.d="3";
    141. tmp.f="4";
    142. ar.StartArchive("a");
    143. ar<
    144. CUnArchive unar;
    145. if(!unar.StartUnArchive("a",&ar.m_buf))return __LINE__;
    146. A tmp2;
    147. unar>>tmp2;
    148. thelog<
    149. thelog<
    150. thelog<
    151. thelog<
    152. thelog<c_str()<
    153. return 0;
    154. }
    155. };
    156. }
    157. #endif

            代码里面用到的buffer类在这里:代码设计:C++ 一个保证带有结束符的缓冲区类(源码)-CSDN博客

            这个类并没有直接写文件,只是把数据写到了buffer里。

            这个类仍然需要对序列化和反序列化写两次代码,仅仅是操作运算符不同(>>和<<),仍然不是很理想,我后来在一个XML配置文件功能里用了这个办法:在类里面用成员变量“bool isSerialize;”来表示处理方向,这样代码就大幅简化,我想或许也可以用在这个类里面。

            参考代码:

    1. //不要直接使用这类,使用CXmlArchive_Save和CXmlArchive_Load
    2. class CXmlArchive
    3. {
    4. private:
    5. bool m_bSave;
    6. TiXmlNode* m_pParentNode;
    7. TiXmlNode* AddOrGet(char const* name)
    8. {
    9. if (m_bSave)
    10. {
    11. return CmyXML::Add(m_pParentNode->ToElement(), name);
    12. }
    13. else
    14. {
    15. return CmyXML::Get(m_pParentNode->ToElement(), name);
    16. }
    17. }
    18. public:
    19. CXmlArchive(bool bSave, TiXmlNode* pParentNode) :m_bSave(bSave), m_pParentNode(pParentNode) {}
    20. bool isSave()const { return m_bSave; }
    21. //通用,必须实现XmlArchive
    22. template<typename T>
    23. CXmlArchive& operator()(char const* name, T& data)
    24. {
    25. CXmlArchive new_archive = *this;
    26. new_archive.m_pParentNode = AddOrGet(name);
    27. data.XmlArchive(new_archive);
    28. return *this;
    29. }
    30. //vector的实现
    31. template<typename T>
    32. CXmlArchive& operator()(char const* name, vector& data)
    33. //String的实现,如果包含中文或以x开头,转码为x开头的16进制
    34. CXmlArchive& operator()(char const* name, CString& data)
    35. CXmlArchive& operator()(char const* name, int& data)
    36. {
    37. if (m_bSave)
    38. {
    39. CmyXML::Add(m_pParentNode->ToElement(), name, data);
    40. }
    41. else
    42. {
    43. CmyXML::Get(m_pParentNode->ToElement(), name, data);
    44. }
    45. return *this;
    46. }
    47. CXmlArchive& operator()(char const* name, double& data)
    48. {
    49. if (m_bSave)
    50. {
    51. CmyXML::Add(m_pParentNode->ToElement(), name, data);
    52. }
    53. else
    54. {
    55. CmyXML::Get(m_pParentNode->ToElement(), name, data);
    56. }
    57. return *this;
    58. }
    59. CXmlArchive& operator()(char const* name, bool& data)
    60. {
    61. if (m_bSave)
    62. {
    63. CmyXML::Add(m_pParentNode->ToElement(), name, data);
    64. }
    65. else
    66. {
    67. CmyXML::Get(m_pParentNode->ToElement(), name, data);
    68. }
    69. return *this;
    70. }
    71. };
    72. class CXmlArchive_Save : public CXmlArchive
    73. {
    74. public:
    75. CXmlArchive_Save(int/*无意义,避免单参数构造函数*/, TiXmlNode* pParentNode) :CXmlArchive(true, pParentNode) {}
    76. };
    77. class CXmlArchive_Load : public CXmlArchive
    78. {
    79. public:
    80. CXmlArchive_Load(int/*无意义,避免单参数构造函数*/, TiXmlNode* pParentNode) :CXmlArchive(false, pParentNode) {}
    81. };

            这个代码用起来是相当舒服的:

    1. //数据类里面增加这个即可,不用关心方向
    2. void XmlArchive(CXmlArchive& ar)
    3. {
    4. ar("ID", ID);
    5. ar("Name", Name);
    6. ar("Status", Status);
    7. }
    8. //保存的时候这样写,其中root是已经打开的tinyXML文档
    9. CXmlArchive_Save ar(0, root);
    10. ar("vList", vDevList);

    (这里是结束)

  • 相关阅读:
    开源库_20210224
    Git 创建分支、合并分支
    2022年深度学习最新研究成果
    关于Java上下转型
    python打开浏览器并模拟搜索
    LVS集群
    Unity角色或摄像机移动和旋转的控制脚本
    如何使用并查集解决朋友圈问题?
    PAA介绍
    2.2线性表的顺序表示-综合应用题(408统考真题10-14)
  • 原文地址:https://blog.csdn.net/2301_77171572/article/details/133920644