剑豪小宝宝 發表於 2025-12-9 09:51:28

C++实现数据的序列化和反序列化详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1.简介</li><li>2.CByteArray设计实现</li><li>3.CDataStream设计实现</li><li>4.使用实例</li></ul></div><p class="maodian"></p><h2>1.简介</h2>
<p>在C++应用程序中,经常会涉及到对一些数据进行序列化和反序列化的处理。序列化可以将一个对象转换为一串字节流,这样就可以将其存储在硬盘上或者通过网络传输到其他设备上。而反序列化则是将这些字节流解析成原始的对象。</p>
<p>在Qt中,数据的序列化和反序列化可以使用QDataStream类来完成。QDataStream是一个方便的Qt类,它可以将基本数据类型、Qt数据类型以及用户定义的数据类型都进行序列化和反序列化。在使用QDataStream进行序列化时,需要指定一个QIODevice类的子类(例如QFile或QBuffer)来将数据写入到文件或者内存中。</p>
<p>示例如下:</p>
<div class="jb51code"><pre class="brush:cpp;">//【1】结构体
typedef struct _stCtrlCmdHeader
{
        unsigned char        rCtrlObj;                               
        unsigned char        rCtrlObjID;                               
        unsigned char        rCtrlCmd;                       
        unsigned short        rDataLen;
public:
        _stCtrlCmdHeader()
        {
                memset(this, 0, sizeof(_stCtrlCmdHeader));
                rCtrlObj = 0x01;
                rCtrlObjID = 0x00;
        }
        friend QDataStream&amp; operator&lt;&lt;(QDataStream&amp; dataStream, const _stCtrlCmdHeader&amp; data)//序列化
        {
                dataStream &lt;&lt; data.rCtrlObj;
                dataStream &lt;&lt; data.rCtrlObjID;
                dataStream &lt;&lt; data.rCtrlCmd;
                dataStream &lt;&lt; data.rDataLen;
                return dataStream;
        }
        friend QDataStream&amp; operator&gt;&gt;(QDataStream&amp; dataStream, _stCtrlCmdHeader&amp; data)       //反序列化
        {
                dataStream &gt;&gt; data.rCtrlObj;
                dataStream &gt;&gt; data.rCtrlObjID;
                dataStream &gt;&gt; data.rCtrlCmd;
                dataStream &gt;&gt; data.rDataLen;
                return dataStream;
        }
}stCtrlCmdHeader;

//【2】序列化到QByteArray
QByteArray data;
QDataStream out(&amp;data, QIODevice::WriteOnly); // we will serialize the data into the data
dataStream.setByteOrder(QDataStream::LittleEndian); //设置小端对齐
out &lt;&lt; QString("the answer is");   // serialize a string
out &lt;&lt; (qint32)42;      // serialize an integer

stCtrlCmdHeader header;
//...
out &lt;&lt; header;   //serializestruct or class

//【3】反序列化
char szBuffer = { 0 };
int len= 0 ;
//...获取网络数据
QByteArray byArray(szBuffer, len);
QDataStream dataStream(&amp;byArray, QIODevice::ReadOnly);
dataStream.setByteOrder(QDataStream::LittleEndian);

char szText = { 0 };
dataStream.readRawData((char*)szText, 10); //unserialize a string

qint32 number = 0;
dataStream &gt;&gt; number ; //unserialize an integer

stCtrlCmdHeader header;
//...
out &gt;&gt; header;   //unserializestruct or class
</pre></div>
<p>在Qt中很方便地可以用到这些类,但是脱离Qt,在标准的C++标准库就没有这么方便了,今天就模仿QByteArray和QDataStream类的接口,写了序列化和反序列化的类CByteArray和CDataStream,可以无缝替换QByteArray和QDataStream,下面就来介绍一下CByteArray和CDataStream的设计和实现。</p>
<p class="maodian"></p><h2>2.CByteArray设计实现</h2>
<p><span><strong>设计要点</strong></span>:</p>
<p>1)&nbsp;CByteArray可以理解是纯字节数组,可以存放任意格式的数据,于是后台用 std::basic_string&lt;char&gt;来存储实际的数据。</p>
<p>2)构造函数接收字符数组(char*+len)</p>
<p>3)&nbsp; 构造函数接受右值引用,实现快速的移动语义</p>
<p>4)重载符号=,接受右值引用,实现快速的移动语义</p>
<p>5)根据长度写入和读取原始数据接口</p>
<div class="jb51code"><pre class="brush:cpp;">int writeRawData(const char* data, PUInt32 size) override;
int readRawData(char* datsa, PUInt32 size) override;</pre></div>
<p>6) 整个类采用Pimpl技法实现</p>
<p>参考:C++中Pimpl的惯用法详解</p>
<p><span><strong>具体实现:</strong></span></p>
<p><strong><span>类型定义:DataType.h</span></strong></p>
<div class="jb51code"><pre class="brush:cpp;">#ifndef _DATA_TYPE_H_
#define _DATA_TYPE_H_

typedefchar               PInt8;
typedef unsigned char       PUInt8;
typedefshort            PInt16;
typedef unsigned short      PUInt16;
typedefint                PInt32;
typedef unsigned int      PUInt32;
typedef long long         PInt64;
typedef unsigned long longPUInt64;
typedef float               PFloat32;
typedef double            PFloat64;

#endif</pre></div>
<p><strong>抽象接口定义如下:IDataBuffer.h</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#ifndef _IDATA_BUFFER_H_
#define _IDATA_BUFFER_H_
#include "DataType.h"

class IDataBuffer
{
public:
    virtual ~IDataBuffer(){}
    virtual int writeBytes(const char*, PUInt32) = 0;
    virtual int readBytes(char*, PUInt32) = 0;
    virtual int writeRawData(const char*, PUInt32) = 0;
    virtual int readRawData(char*, PUInt32) = 0;
    virtual int bytesAvailable() const = 0;
    virtual PUInt64 skip(PUInt64 maxSize) = 0;
};

#endif
</pre></div>
<p><strong>ByteArray.h</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#ifndef _BYTE_ARRAY_H_
#define _BYTE_ARRAY_H_
#include &lt;string&gt;
#include &lt;memory&gt;
#include "IDataBuffer.h"

class CByteArrayPrivate;
class CByteArray : public IDataBuffer
{
public:
    explicit CByteArray();
    CByteArray(const CByteArray&amp; other);
    CByteArray(CByteArray&amp;&amp; other);
    CByteArray(const char* buffer, int size);
    CByteArray&amp; operator=(CByteArray&amp;&amp; other);
    operator bool() const;
    virtual ~CByteArray();

public:
    int writeRawData(const char* data, PUInt32 size) override;
    int readRawData(char* datsa, PUInt32 size) override;

    int writeBytes(const char*, PUInt32) override;
    int readBytes(char*, PUInt32) override;

    const char* data() const;
    intsize() const;

    int bytesAvailable() const override;

    PUInt64 skip(PUInt64 maxSize) override;

    CByteArray&amp; append(const char* data, PUInt32 size);
    CByteArray&amp; append(const char* data);

    voidclear();

private:
    std::unique_ptr&lt;CByteArrayPrivate&gt; d_ptr;
};

#endif
</pre></div>
<p><strong>ByteArray.cpp</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include "ByteArray.h"
#include &lt;assert.h&gt;
#include &lt;string.h&gt;
//#include &lt;string_view&gt;

class CByteArrayPrivate
{
public:
    explicit CByteArrayPrivate():m_readPos(0) {}
    CByteArrayPrivate(const char* buffer, int size): m_buffer(buffer, size), m_readPos(0) {}

    //这个类,有点类似于Golang语言中的切片Slice。这就意味着std::string_view本身并不拥有内存本身,
    //它只是一个View,一个窗口,观看内存的窗口
    //std::string_viewm_buffer;
    std::basic_string&lt;char&gt;m_buffer;
    intm_readPos; //暂时没用
};

CByteArray::CByteArray()
    : d_ptr(new CByteArrayPrivate)
{

}

CByteArray::CByteArray(const CByteArray&amp; other)
    : d_ptr(new CByteArrayPrivate)
{
    d_ptr-&gt;m_buffer = other.d_ptr-&gt;m_buffer;
    d_ptr-&gt;m_readPos = other.d_ptr-&gt;m_readPos;
}

CByteArray::CByteArray(CByteArray&amp;&amp; other)
    : d_ptr(other.d_ptr.release())
{
    other.d_ptr.reset(new CByteArrayPrivate);
}

CByteArray::CByteArray(const char* buffer, int size)
    : d_ptr(new CByteArrayPrivate(buffer,size))
{

}

CByteArray::operator bool() const
{
    return (0 ==size());
}

CByteArray&amp; CByteArray::operator=(CByteArray&amp;&amp; other)
{
    if (d_ptr == other.d_ptr){
      return *this;
    }
    CByteArrayPrivate* temp = d_ptr.release();
    d_ptr.reset(other.d_ptr.release());
    other.d_ptr.reset(temp);
    return *this;
}

CByteArray::~CByteArray()
{

}

int CByteArray::writeRawData(const char* data, PUInt32 size)
{
    d_ptr-&gt;m_buffer.append(data, size);
    return size;
}
int CByteArray::readRawData(char* data, PUInt32 size)
{
    if (d_ptr-&gt;m_buffer.copy(data, size, 0) != size){
      assert(0);
      return 0;
    }
    d_ptr-&gt;m_buffer.erase(0, size);
    return size;
}
const char* CByteArray::data() const
{
    return d_ptr-&gt;m_buffer.data();
}
intCByteArray::size() const
{
    return d_ptr-&gt;m_buffer.size();
}
int CByteArray::bytesAvailable() const
{
    return size();
}
PUInt64 CByteArray::skip(PUInt64 maxSize)
{
    PUInt64 nSkip = maxSize;
    if (maxSize &gt;= d_ptr-&gt;m_buffer.size()){
      nSkip = d_ptr-&gt;m_buffer.size();
      d_ptr-&gt;m_buffer.clear();
      return nSkip;
    }else{
      d_ptr-&gt;m_buffer.erase(0, maxSize);
      return nSkip;
    }
}
int CByteArray::writeBytes(const char*, PUInt32)
{
    assert(0);
    return 0;
}
int CByteArray::readBytes(char*, PUInt32)
{
    assert(0);
    return 0;
}

CByteArray&amp; CByteArray::append(const char* data, PUInt32 size)
{
    d_ptr-&gt;m_buffer.append(data, size);
    return *this;
}

CByteArray&amp; CByteArray::append(const char* data)
{
    if (!data){
      return *this;
    }

    int len = strlen(data);
    return append(data, len);
}

voidCByteArray::clear() {
    d_ptr-&gt;m_buffer.clear();
}
</pre></div>
<p class="maodian"></p><h2>3.CDataStream设计实现</h2>
<p><span><strong>设计要点:</strong></span></p>
<p>1)&nbsp; 支持所有支持IDataBuffer的实现类</p>
<p>2)支持C++的基本数据类型序列化和反序列化,重载operator&lt;&lt;和operator&gt;&gt;</p>
<p>3)&nbsp; 支持自定义数据类型的序列化和反序列化,如结构体或类</p>
<p>4)反序列化时,可以忽略指定的字节</p>
<p>5)反序列化可变字节长度时,可以获取未序列化的数据长度,用户获取长度申请空间并反序列化到指定的内存中</p>
<p><span><strong>具体实现:</strong></span></p>
<p>ShortWaveToolFun.h</p>
<div class="jb51code"><pre class="brush:cpp;">#ifndef _SHORT_WAVE_TOOL_FUNC_H_
#define _SHORT_WAVE_TOOL_FUNC_H_
#include &lt;string&gt;
#include "DataType.h"
#include &lt;functional&gt;
#include &lt;memory&gt;
#include &lt;string.h&gt;

#define WORK_MSG_ID(link, type, sub)( (link&lt;&lt;16) | (type&lt;&lt;8) | sub )
#define GET_WORK_TYPE(id)   ((id &gt;&gt; 8) &amp; 0xff)
#define GET_WORK_CMD(id)    (id &amp; 0xff)
#define GET_WORK_B_TYPE(id)   ((id &gt;&gt; 16) &amp; 0xff)

#define MEMBER_OFF_SET(type, member) ((size_t) &amp;(static_cast&lt;type*&gt;(0))-&gt;member)

#define CONTAINER_OF(ptr, type, member) ({ \
       const typeof(((type*)0)-&gt;member) * __mptr = (ptr);   \
       (type*)((char*)__mptr - MEMBER_OFF_SET(type,member)); })

template &lt;typename T, class = typename std::enable_if&lt;sizeof(T)%2==0&gt;::type&gt;
TreverseNumber(T value)
{
    static_assert(sizeof(T)%2==0, "T type is invalid!!!");

    union X{
      T val1;
      char val2;
    };

    int i = 0;
    int size = sizeof(T);
    char temp = 0;
    X x;
    x.val1 = value;

    for (i = 0; i &lt; sizeof(T)/2; i++){
      temp = x.val2;
      x.val2 = x.val2;
      x.val2 = temp;
    }
    return x.val1;
}

template &lt;typename T, class = typename std::enable_if&lt;sizeof(T)&lt;=sizeof(PUInt64)&gt;::type&gt;
PUInt64transTToPUInt64(T value)
{
    static_assert(sizeof(T)&lt;=sizeof(PUInt64), "T type is invalid!!!");

    union X{
      T val1;
      PUInt64 val2;
    };
    X x;
    x.val2 = 0; //将高位置0
    x.val1 = value;
    return x.val2;
}

template &lt;typename T, class = typename std::enable_if&lt;sizeof(T)&lt;=sizeof(PUInt64)&gt;::type&gt;
TtransPUInt64ToT(PUInt64 value)
{
    static_assert(sizeof(T)&lt;=sizeof(PUInt64), "T type is invalid!!!");

    union X{
      T val1;
      PUInt64 val2;
    };
    X x;
    x.val2 = value;
    return x.val1;
}

#endif
</pre></div>
<p><strong>DataStream.h</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#ifndef _DATA_STREAM_H_
#define _DATA_STREAM_H_
#include "DataType.h"

class IDataBuffer;
class CByteArray;
class CDataStream
{
public:
    explicit CDataStream(IDataBuffer* pBuffer);
    ~CDataStream();

    bool bigEndian() const;
    void setBigEndian(bool newBigEndian);

    CDataStream&amp; operator&lt;&lt;(bool i);
    CDataStream&amp; operator&lt;&lt;(PInt8 i);
    CDataStream&amp; operator&lt;&lt;(PUInt8 i);
    CDataStream&amp; operator&lt;&lt;(PInt16 i);
    CDataStream&amp; operator&lt;&lt;(PUInt16 i);
    CDataStream&amp; operator&lt;&lt;(PInt32 i);
    CDataStream&amp; operator&lt;&lt;(PUInt32 i);
    CDataStream&amp; operator&lt;&lt;(PInt64 i);
    CDataStream&amp; operator&lt;&lt;(PUInt64 i);
    CDataStream&amp; operator&lt;&lt;(PFloat32 i);
    CDataStream&amp; operator&lt;&lt;(PFloat64 i);
    CDataStream&amp; operator&lt;&lt;(const char* i);
    CDataStream&amp; operator&lt;&lt;(const CByteArray&amp; data);
    template &lt;typename T&gt;
    CDataStream&amp; operator&lt;&lt;(const T&amp; t)
    {
      (*this) &lt;&lt; t;
      return *this;
    }

    CDataStream&amp; operator&gt;&gt;(bool&amp; i);
    CDataStream&amp; operator&gt;&gt;(PInt8&amp; i);
    CDataStream&amp; operator&gt;&gt;(PUInt8&amp; i);
    CDataStream&amp; operator&gt;&gt;(PInt16&amp; i);
    CDataStream&amp; operator&gt;&gt;(PUInt16&amp; i);
    CDataStream&amp; operator&gt;&gt;(PInt32&amp; i);
    CDataStream&amp; operator&gt;&gt;(PUInt32&amp; i);
    CDataStream&amp; operator&gt;&gt;(PInt64&amp; i);
    CDataStream&amp; operator&gt;&gt;(PUInt64&amp; i);
    CDataStream&amp; operator&gt;&gt;(PFloat32&amp; i);
    CDataStream&amp; operator&gt;&gt;(PFloat64&amp; i);
    CDataStream&amp; operator&gt;&gt;(char*&amp; i);
    CDataStream&amp; operator&gt;&gt;(CByteArray&amp; data);
    template &lt;typename T&gt;
    CDataStream&amp; operator&gt;&gt;(T&amp; t)
    {
      (*this) &gt;&gt; t;
      return *this;
    }

    int writeRawData(const char* data, PUInt32 size);
    int readRawData(char* data, PUInt32 size);

    boolatEnd() const;
    int   bytesAvailable() const;

    int skipRawData(int len);

private:
    boolm_bigEndian;
    IDataBuffer* m_buffer;
};

#endif
</pre></div>
<p><strong>DataStream.cpp</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include "IDataBuffer.h"
#include "DataStream.h"
#include "ShortWaveToolFun.h"
#include &lt;string.h&gt;
#include "ByteArray.h"

CDataStream::CDataStream(IDataBuffer* pBuffer)
    : m_bigEndian(false)
    , m_buffer(pBuffer)
{

}

CDataStream::~CDataStream()
{

}

bool CDataStream::bigEndian() const
{
    return m_bigEndian;
}

void CDataStream::setBigEndian(bool newBigEndian)
{
    m_bigEndian = newBigEndian;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(bool i)
{
    *this &lt;&lt; (PInt8)i;
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PInt8 i)
{
    PInt8 ch = i;
    m_buffer-&gt;writeRawData(&amp;ch, sizeof(ch));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PUInt8 i)
{
    PInt8 ch = i;
    m_buffer-&gt;writeRawData(&amp;ch, sizeof(ch));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PInt16 i)
{
    PInt16 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PUInt16 i)
{
    PUInt16 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PInt32 i)
{
    PInt32 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PUInt32 i)
{
    PUInt32 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PInt64 i)
{
    PInt64 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PUInt64 i)
{
    PUInt64 temp = i;
    if (m_bigEndian){
      temp = reverseNumber(i);
    }
    m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(temp));
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PFloat32 i)
{
    PFloat32 temp = i;
    if (m_bigEndian){
      union {
            float val1;
            PUInt32 val2;
      } x;
      x.val1 = i;
      x.val2 = reverseNumber(x.val2);
      m_buffer-&gt;writeRawData((char*)&amp;x.val2, sizeof(i));
    }else{
      m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(i));
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&lt;&lt;(PFloat64 i)
{
    PFloat64 temp = i;
    if (m_bigEndian){
      union {
            double val1;
            PUInt64 val2;
      } x;
      x.val1 = i;
      x.val2 = reverseNumber(x.val2);
      m_buffer-&gt;writeRawData((char*)&amp;x.val2, sizeof(i));
    }else{
      m_buffer-&gt;writeRawData((char*)&amp;temp, sizeof(i));
    }
    return *this;
}

CDataStream&amp; CDataStream::operator&lt;&lt;(const char* i)
{
    if (!i) {
      *this &lt;&lt; (PUInt32)0;
      return *this;
    }
    int len = strlen(i) + 1;
    *this &lt;&lt; (PUInt32)len;
    m_buffer-&gt;writeRawData(i, len);
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(bool&amp; i)
{
    PInt8 v;
    *this &gt;&gt; v;
    i = !!v;
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PInt8&amp; i)
{
    m_buffer-&gt;readRawData(&amp;i, 1);
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PUInt8&amp; i)
{
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PInt16&amp; i)
{
    m_buffer-&gt;readRawData((char *)(&amp;i), sizeof(i));
    if (m_bigEndian){
      i = reverseNumber(i);
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PUInt16&amp; i)
{
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    if (m_bigEndian){
      i = reverseNumber(i);
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PInt32&amp; i)
{
    m_buffer-&gt;readRawData((char *)(&amp;i), sizeof(i));
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PUInt32&amp; i)
{
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    if (m_bigEndian){
      i = reverseNumber(i);
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PInt64&amp; i)
{
    m_buffer-&gt;readRawData((char *)(&amp;i), sizeof(i));
    if (m_bigEndian){
      i = reverseNumber(i);
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PUInt64&amp; i)
{
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    if (m_bigEndian){
      i = reverseNumber(i);
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PFloat32&amp; i)
{
    i = 0.0f;
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    if (m_bigEndian){
      union {
            float val1;
            PUInt32 val2;
      } x;
      x.val2 = reverseNumber(*reinterpret_cast&lt;PUInt32 *&gt;(&amp;i));
      i = x.val1;
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(PFloat64&amp; i)
{
    i = 0.0f;
    m_buffer-&gt;readRawData(reinterpret_cast&lt;char *&gt;(&amp;i), sizeof(i));
    if (m_bigEndian){
      union {
            double val1;
            PUInt64 val2;
      } x;
      x.val2 = reverseNumber(*reinterpret_cast&lt;PUInt64 *&gt;(&amp;i));
      i = x.val1;
    }
    return *this;
}
CDataStream&amp; CDataStream::operator&gt;&gt;(char*&amp; i)
{
    PUInt32 len = 0;
    *this &gt;&gt; len;
    if (len == 0)
      return *this;

    m_buffer-&gt;readRawData(i, len);

    i = '\0';
    return *this;
}

CDataStream&amp; CDataStream::operator&lt;&lt;(const CByteArray&amp; data)
{
    m_buffer-&gt;writeRawData(data.data(), data.size());
    return *this;
}

CDataStream&amp; CDataStream::operator&gt;&gt;(CByteArray&amp; data)
{
    PUInt32 len = 0;
    *this &gt;&gt; len;
    if (len == 0)
      return *this;

    std::unique_ptr&lt;char[]&gt; pBuffer(new char);
    m_buffer-&gt;readRawData(pBuffer.get(), len);

    data.append(pBuffer.get(), len);
    return *this;
}

int CDataStream::writeRawData(const char* data, PUInt32 size)
{
    return m_buffer-&gt;writeRawData(data, size);
}
int CDataStream::readRawData(char* data, PUInt32 size)
{
    return m_buffer-&gt;readRawData(data, size);
}

boolCDataStream::atEnd() const
{
    return m_buffer-&gt;bytesAvailable() &lt;= 0;
}

int   CDataStream::bytesAvailable() const
{
    return m_buffer-&gt;bytesAvailable();
}

int CDataStream::skipRawData(int len)
{
    return m_buffer-&gt;skip(len);
}</pre></div>
<p class="maodian"></p><h2>4.使用实例</h2>
<p>结构体定义:</p>
<div class="jb51code"><pre class="brush:cpp;">//传输的整个报文
typedefstruct_stShortWavePacket
{
        //共用
        PUInt32            contextID;
        void* pAppData; //正文数据

        PUInt16            frameIndex;
        stObjectFlag      srcObjMark;
        stObjectFlag      destObjMark;
        PUInt8             isMustResponse;
        PUInt8                           responseStatus;

public:
        _stShortWavePacket() {
        }

}stShortWavePacket;

using stChannelWorkParamData = KVData&lt;PUInt16, PUInt64&gt;;
using ChannelWorkParamDataContainer = std::vector&lt;std::shared_ptr&lt;stChannelWorkParamData&gt;&gt;;

//结构体定义
template &lt;bool isHaveType&gt;
struct stChannelWorkParam
{
        PUInt16    signalType; //类别
    ChannelWorkParamDataContainer workParamData;

public:
        stChannelWorkParam() {
                signalType = 0;
        }
        stChannelWorkParam(const stChannelWorkParam&amp;) = delete;
        stChannelWorkParam&amp; operator=(const stChannelWorkParam&amp;) = delete;
        PUInt16getDataSize() {
                PUInt16 size = isHaveType ? 2 : 0;
                for (auto&amp; it : workParamData) {
                        size += it-&gt;getSize();
                }
                return size;
        }
        std::stringtoString() const {
                return std::string("type:") + numConvertString(signalType);
        }
        friend CDataStream&amp; operator&lt;&lt;(CDataStream&amp; dataStream, const stChannelWorkParam&amp; data)
        {
                if (isHaveType) {
                        dataStream &lt;&lt; data.signalType;
                }
                for (auto&amp; it : data.workParamData) {
                        it-&gt;serializeData(dataStream);
                }
                return dataStream;
        }
        friend CDataStream&amp; operator&gt;&gt;(CDataStream&amp; dataStream, stChannelWorkParam&amp; data)
        {
                if (isHaveType) {
                        dataStream &gt;&gt; data.signalType;
                }
                while (dataStream.bytesAvailable() &gt; 6) {
                        std::shared_ptr&lt;stChannelWorkParamData&gt; pData = std::make_shared&lt;stChannelWorkParamData&gt;();
                        pData-&gt;unserializeData(dataStream);
                        data.workParamData.push_back(pData);
                }
                return dataStream;
        }
};
usingstSendChannelWorkParam = stChannelWorkParam&lt;true&gt;;
usingstUploadRegisterStatus = stChannelWorkParam&lt;false&gt;;</pre></div>
<p>序列化数据:</p>
<div class="jb51code"><pre class="brush:cpp;">template &lt;PUInt32 type, typename stType&gt;
intencodeData(char* data, int&amp; len, const stShortWavePacket* pPacket)
{
    PUInt16 crcCode = 0;
    CByteArraybyArray;
    CDataStream dataStream(&amp;byArray);

    stType* pMessage = reinterpret_cast&lt;stType*&gt;(pPacket-&gt;pAppData);
    if (pMessage == nullptr)
      return 1;
    //
    dataStream.writeRawData((const char*)m_startFlag, sizeof(m_startFlag));
    dataStream &lt;&lt; getFrameNo();
    dataStream &lt;&lt; pPacket-&gt;srcObjMark.data;
    dataStream &lt;&lt; pPacket-&gt;destObjMark.data;
    dataStream &lt;&lt; pPacket-&gt;isMustResponse;
    dataStream &lt;&lt; (PUInt8)GET_WORK_TYPE(type);
    dataStream &lt;&lt; pMessage-&gt;getDataSize();

    //
    dataStream &lt;&lt; (*pMessage);

    crcCode = getCRCCode(byArray.data(), byArray.size());
    dataStream &lt;&lt; crcCode;
    dataStream.writeRawData((const char*)m_endFlag, sizeof(m_endFlag));
    len = byArray.size();
    memcpy(data, byArray.data(), len);
    return 0;
}</pre></div>
<p>接收到网络数据,反序列化数据:</p>
<div class="jb51code"><pre class="brush:cpp;">template &lt;PUInt32 type, typename stType&gt;
intparseData(const char* data, int len, stShortWavePacket* pPacket)
{
    CByteArray byArray(data, len);
    CDataStream dataStream(&amp;byArray);

    PUInt16 length = 0;

    pPacket-&gt;contextID = type;
    dataStream.skipRawData(4);   //忽略4个字节
    dataStream &gt;&gt; pPacket-&gt;frameIndex;
    m_frameNo = pPacket-&gt;frameIndex;
    dataStream &gt;&gt; pPacket-&gt;srcObjMark.data;
    dataStream &gt;&gt; pPacket-&gt;destObjMark.data;
    dataStream &gt;&gt; pPacket-&gt;isMustResponse; //是否应答
    dataStream.skipRawData(1); //忽略功能指令,1个字节
    dataStream &gt;&gt; length;
    if (length != stType::getDataSize())
            return -1;

    std::unique_ptr&lt;stType&gt; pAppData = std::make_unique&lt;stType&gt;();
    dataStream &gt;&gt; (*pAppData);

    pPacket-&gt;pAppData = pAppData.release();
    return 0;
}</pre></div>
<p>到此这篇关于C++实现数据的序列化和反序列化详解的文章就介绍到这了,更多相关C++数据序列化和反序列化内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C++如何通过Qt反射机制实现数据类序列化</li><li>C++中二进制数据序列化和反序列化详解</li><li>C++内存数据结构与二进制文件之间的序列化和反序列化方式</li><li>C++数据序列化方式(自定义结构体的保存和读取)</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: C++实现数据的序列化和反序列化详解