手撕代码: C++实现数据的序列化和反序列化

目录

1.简介

2.CByteArray设计实现

3.CDataStream设计实现

4.使用实例

5.总结


1.简介

        在C++应用程序中,经常会涉及到对一些数据进行序列化和反序列化的处理。序列化可以将一个对象转换为一串字节流,这样就可以将其存储在硬盘上或者通过网络传输到其他设备上。而反序列化则是将这些字节流解析成原始的对象。

        在Qt中,数据的序列化和反序列化可以使用QDataStream类来完成。QDataStream是一个方便的Qt类,它可以将基本数据类型、Qt数据类型以及用户定义的数据类型都进行序列化和反序列化。在使用QDataStream进行序列化时,需要指定一个QIODevice类的子类(例如QFile或QBuffer)来将数据写入到文件或者内存中。

        示例如下:

//【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& operator<<(QDataStream& dataStream, const _stCtrlCmdHeader& data)  //序列化
	{
		dataStream << data.rCtrlObj;
		dataStream << data.rCtrlObjID;
		dataStream << data.rCtrlCmd;
		dataStream << data.rDataLen;
		return dataStream;
	}
	friend QDataStream& operator>>(QDataStream& dataStream, _stCtrlCmdHeader& data)       //反序列化
	{
		dataStream >> data.rCtrlObj;
		dataStream >> data.rCtrlObjID;
		dataStream >> data.rCtrlCmd;
		dataStream >> data.rDataLen;
		return dataStream;
	}
}stCtrlCmdHeader;

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

stCtrlCmdHeader header;
//...
out << header;     //serialize  struct or class

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

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

qint32 number = 0;
dataStream >> number ; //unserialize an integer

stCtrlCmdHeader header;
//...
out >> header;     //unserialize  struct or class

在Qt中很方便地可以用到这些类,但是脱离Qt,在标准的C++标准库就没有这么方便了,今天就模仿QByteArray和QDataStream类的接口,写了序列化和反序列化的类CByteArray和CDataStream,可以无缝替换QByteArray和QDataStream,下面就来介绍一下CByteArray和CDataStream的设计和实现。

2.CByteArray设计实现

设计要点

1) CByteArray可以理解是纯字节数组,可以存放任意格式的数据,于是后台用 std::basic_string<char>来存储实际的数据。

2)构造函数接收字符数组(char*+len)

3)  构造函数接受右值引用,实现快速的移动语义

4)重载符号=,接受右值引用,实现快速的移动语义

5)根据长度写入和读取原始数据接口

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

6) 整个类采用Pimpl技法实现

C++惯用法之Pimpl-CSDN博客

具体实现:

类型定义:DataType.h

#ifndef _DATA_TYPE_H_
#define _DATA_TYPE_H_

typedef  char               PInt8;
typedef unsigned char       PUInt8;
typedef  short              PInt16;
typedef unsigned short      PUInt16;
typedef  int                PInt32;
typedef unsigned int        PUInt32;
typedef long long           PInt64;
typedef unsigned long long  PUInt64;
typedef float               PFloat32;
typedef double              PFloat64;

#endif

抽象接口定义如下:IDataBuffer.h

#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

ByteArray.h

#ifndef _BYTE_ARRAY_H_
#define _BYTE_ARRAY_H_
#include <string>
#include <memory>
#include "IDataBuffer.h"

class CByteArrayPrivate;
class CByteArray : public IDataBuffer
{
public:
    explicit CByteArray();
    CByteArray(const CByteArray& other);
    CByteArray(CByteArray&& other);
    CByteArray(const char* buffer, int size);
    CByteArray& operator=(CByteArray&& 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;
    int  size() const;

    int bytesAvailable() const override;

    PUInt64 skip(PUInt64 maxSize) override;

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

    void  clear();

private:
    std::unique_ptr<CByteArrayPrivate> d_ptr;
};

#endif

ByteArray.cpp

#include "ByteArray.h"
#include <assert.h>
#include <string.h>
//#include <string_view>

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_view  m_buffer;
    std::basic_string<char>  m_buffer;
    int  m_readPos; //暂时没用
};

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

}

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

CByteArray::CByteArray(CByteArray&& 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& CByteArray::operator=(CByteArray&& 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->m_buffer.append(data, size);
    return size;
}
int CByteArray::readRawData(char* data, PUInt32 size)
{
    if (d_ptr->m_buffer.copy(data, size, 0) != size){
        assert(0);
        return 0;
    }
    d_ptr->m_buffer.erase(0, size);
    return size;
}
const char* CByteArray::data() const
{
    return d_ptr->m_buffer.data();
}
int  CByteArray::size() const
{
    return d_ptr->m_buffer.size();
}
int CByteArray::bytesAvailable() const
{
    return size();
}
PUInt64 CByteArray::skip(PUInt64 maxSize)
{
    PUInt64 nSkip = maxSize;
    if (maxSize >= d_ptr->m_buffer.size()){
        nSkip = d_ptr->m_buffer.size();
        d_ptr->m_buffer.clear();
        return nSkip;
    }else{
        d_ptr->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& CByteArray::append(const char* data, PUInt32 size)
{
    d_ptr->m_buffer.append(data, size);
    return *this;
}

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

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

void  CByteArray::clear() {
    d_ptr->m_buffer.clear();
}

3.CDataStream设计实现

设计要点:

1)  支持所有支持IDataBuffer的实现类

2)支持C++的基本数据类型序列化和反序列化,重载operator<<和operator>>

3)  支持自定义数据类型的序列化和反序列化,如结构体或类

4)反序列化时,可以忽略指定的字节

5)反序列化可变字节长度时,可以获取未序列化的数据长度,用户获取长度申请空间并反序列化到指定的内存中

具体实现:

ShortWaveToolFun.h

#ifndef _SHORT_WAVE_TOOL_FUNC_H_
#define _SHORT_WAVE_TOOL_FUNC_H_
#include <string>
#include "DataType.h"
#include <functional>
#include <memory>
#include <string.h>

#define WORK_MSG_ID(link, type, sub)  ( (link<<16) | (type<<8) | sub )
#define GET_WORK_TYPE(id)   ((id >> 8) & 0xff)
#define GET_WORK_CMD(id)    (id & 0xff)
#define GET_WORK_B_TYPE(id)   ((id >> 16) & 0xff)

#define MEMBER_OFF_SET(type, member) ((size_t) &(static_cast<type*>(0))->member)

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

template <typename T, class = typename std::enable_if<sizeof(T)%2==0>::type>
T  reverseNumber(T value)
{
    static_assert(sizeof(T)%2==0, "T type is invalid!!!");

    union X{
        T val1;
        char val2[sizeof(T)];
    };

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

    for (i = 0; i < sizeof(T)/2; i++){
        temp = x.val2[i];
        x.val2[i] = x.val2[size-i-1];
        x.val2[size-i-1] = temp;
    }
    return x.val1;
}

template <typename T, class = typename std::enable_if<sizeof(T)<=sizeof(PUInt64)>::type>
PUInt64  transTToPUInt64(T value)
{
    static_assert(sizeof(T)<=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 <typename T, class = typename std::enable_if<sizeof(T)<=sizeof(PUInt64)>::type>
T  transPUInt64ToT(PUInt64 value)
{
    static_assert(sizeof(T)<=sizeof(PUInt64), "T type is invalid!!!");

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

#endif

DataStream.h

#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& operator<<(bool i);
    CDataStream& operator<<(PInt8 i);
    CDataStream& operator<<(PUInt8 i);
    CDataStream& operator<<(PInt16 i);
    CDataStream& operator<<(PUInt16 i);
    CDataStream& operator<<(PInt32 i);
    CDataStream& operator<<(PUInt32 i);
    CDataStream& operator<<(PInt64 i);
    CDataStream& operator<<(PUInt64 i);
    CDataStream& operator<<(PFloat32 i);
    CDataStream& operator<<(PFloat64 i);
    CDataStream& operator<<(const char* i);
    CDataStream& operator<<(const CByteArray& data);
    template <typename T>
    CDataStream& operator<<(const T& t)
    {
        (*this) << t;
        return *this;
    }

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

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

    bool  atEnd() const;
    int   bytesAvailable() const;

    int skipRawData(int len);

private:
    bool  m_bigEndian;
    IDataBuffer* m_buffer;
};

#endif

DataStream.cpp

#include "IDataBuffer.h"
#include "DataStream.h"
#include "ShortWaveToolFun.h"
#include <string.h>
#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& CDataStream::operator<<(bool i)
{
    *this << (PInt8)i;
    return *this;
}
CDataStream& CDataStream::operator<<(PInt8 i)
{
    PInt8 ch = i;
    m_buffer->writeRawData(&ch, sizeof(ch));
    return *this;
}
CDataStream& CDataStream::operator<<(PUInt8 i)
{
    PInt8 ch = i;
    m_buffer->writeRawData(&ch, sizeof(ch));
    return *this;
}
CDataStream& CDataStream::operator<<(PInt16 i)
{
    PInt16 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PUInt16 i)
{
    PUInt16 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PInt32 i)
{
    PInt32 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PUInt32 i)
{
    PUInt32 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PInt64 i)
{
    PInt64 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PUInt64 i)
{
    PUInt64 temp = i;
    if (m_bigEndian){
        temp = reverseNumber(i);
    }
    m_buffer->writeRawData((char*)&temp, sizeof(temp));
    return *this;
}
CDataStream& CDataStream::operator<<(PFloat32 i)
{
    PFloat32 temp = i;
    if (m_bigEndian){
        union {
            float val1;
            PUInt32 val2;
        } x;
        x.val1 = i;
        x.val2 = reverseNumber(x.val2);
        m_buffer->writeRawData((char*)&x.val2, sizeof(i));
    }else{
        m_buffer->writeRawData((char*)&temp, sizeof(i));
    }
    return *this;
}
CDataStream& CDataStream::operator<<(PFloat64 i)
{
    PFloat64 temp = i;
    if (m_bigEndian){
        union {
            double val1;
            PUInt64 val2;
        } x;
        x.val1 = i;
        x.val2 = reverseNumber(x.val2);
        m_buffer->writeRawData((char*)&x.val2, sizeof(i));
    }else{
        m_buffer->writeRawData((char*)&temp, sizeof(i));
    }
    return *this;
}

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

    m_buffer->readRawData(i, len);

    i[len] = '\0';
    return *this;
}

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

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

    std::unique_ptr<char[]> pBuffer(new char[len]);
    m_buffer->readRawData(pBuffer.get(), len);

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

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

bool  CDataStream::atEnd() const
{
    return m_buffer->bytesAvailable() <= 0;
}

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

int CDataStream::skipRawData(int len)
{
    return m_buffer->skip(len);
}

4.使用实例

结构体定义:

//传输的整个报文
typedef  struct  _stShortWavePacket
{
	//共用
	PUInt32            contextID;
	void* pAppData; //正文数据

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

public:
	_stShortWavePacket() {
	}

}stShortWavePacket;

using stChannelWorkParamData = KVData<PUInt16, PUInt64>;
using ChannelWorkParamDataContainer = std::vector<std::shared_ptr<stChannelWorkParamData>>;

//结构体定义
template <bool isHaveType>
struct stChannelWorkParam
{
	PUInt16    signalType; //类别
    ChannelWorkParamDataContainer workParamData;

public:
	stChannelWorkParam() {
		signalType = 0;
	}
	stChannelWorkParam(const stChannelWorkParam&) = delete;
	stChannelWorkParam& operator=(const stChannelWorkParam&) = delete;
	PUInt16  getDataSize() {
		PUInt16 size = isHaveType ? 2 : 0;
		for (auto& it : workParamData) {
			size += it->getSize();
		}
		return size;
	}
	std::string  toString() const {
		return std::string("type:") + numConvertString(signalType);
	}
	friend CDataStream& operator<<(CDataStream& dataStream, const stChannelWorkParam& data)
	{
		if (isHaveType) {
			dataStream << data.signalType;
		}
		for (auto& it : data.workParamData) {
			it->serializeData(dataStream);
		}
		return dataStream;
	}
	friend CDataStream& operator>>(CDataStream& dataStream, stChannelWorkParam& data)
	{
		if (isHaveType) {
			dataStream >> data.signalType;
		}
		while (dataStream.bytesAvailable() > 6) {
			std::shared_ptr<stChannelWorkParamData> pData = std::make_shared<stChannelWorkParamData>();
			pData->unserializeData(dataStream);
			data.workParamData.push_back(pData);
		}
		return dataStream;
	}
};
using  stSendChannelWorkParam = stChannelWorkParam<true>;
using  stUploadRegisterStatus = stChannelWorkParam<false>;

序列化数据:

template <PUInt32 type, typename stType>
int  encodeData(char* data, int& len, const stShortWavePacket* pPacket)
{
    PUInt16 crcCode = 0;
    CByteArray  byArray;
    CDataStream dataStream(&byArray);

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

    //[2]
    dataStream << (*pMessage);

    crcCode = getCRCCode(byArray.data(), byArray.size());
    dataStream << crcCode;
    dataStream.writeRawData((const char*)m_endFlag, sizeof(m_endFlag));
    len = byArray.size();
    memcpy(data, byArray.data(), len);
    return 0;
}

接收到网络数据,反序列化数据:

template <PUInt32 type, typename stType>
int  parseData(const char* data, int len, stShortWavePacket* pPacket)
{
    CByteArray byArray(data, len);
    CDataStream dataStream(&byArray);

    PUInt16 length = 0;

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

    std::unique_ptr<stType> pAppData = std::make_unique<stType>();
    dataStream >> (*pAppData);

    pPacket->pAppData = pAppData.release();
    return 0;
}

5.总结

        以上代码都是我项目上用到的代码,绝对有效。也希望可以帮到有需求的朋友。如果有不明白的地方,也可以私信我。

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
引用\[1\]:要想使用网络框架的API来传输结构化的数据,必须得先实现结构化的数据与字节流之间的双向转换。这种将结构化数据转换成字节流的过程,称为序列化,反过来转换,就是反序列化。简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它依据流重构对象。\[2\]在C++中,可以使用一些库或框架来实现序列化反序列化。比如,可以使用Boost库中的Serialization模块来实现对象的序列化反序列化。Boost.Serialization提供了一种简单的方式来将C++对象序列化为字节流,并将字节流反序列化为原始对象。此外,C++标准库中也提供了一些序列化反序列化的功能,比如使用iostream库中的<<和>>运算符重载来实现对象的序列化反序列化。另外,还可以使用Google的Protocol Buffers库来实现C++对象的序列化反序列化。这个库提供了一种语言无关、平台无关、可扩展的序列化机制,可以将结构化数据序列化为二进制格式,以便在不同的系统之间进行数据交换。总之,C++中有多种方法可以实现对象的序列化反序列化,具体选择哪种方法取决于具体的需求和使用场景。 #### 引用[.reference_title] - *1* *2* [C++ 序列化反序列化](https://blog.csdn.net/JMW1407/article/details/107173775)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [c++序列化以及反序列化实现](https://blog.csdn.net/qq_33521184/article/details/125228533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值