Qt开发技术【C++ 实现类的二进制序列化与反序列化】
一、思考 Qt 本身的QByteArray 和QDataStream
QDataStream和QByteArray是Qt框架中用于数据序列化和反序列化的类。QDataStream可以将Qt数据类型(如QString、QByteArray等)序列化为二进制格式,并写入文件或网络流中。同时,也可以从文件或网络流中读取二进制数据并反序列化成相应的数据类型。
但是在嵌入式中使用代码比较冗余
二、实现一个比较简单的仅对部分类型进行序列化的类
例如常用的uint8_t uint16_t uint32_t 嵌入式通信常用的几种类型
想法是继承 class CBinarySerializer 实习序列化函数
virtual bool Serialize2Buffer(bool bIsSerialize)
/*
* @brief 二进制序列化类
*/
class CBinarySerializer
{
public:
enum E_BYTE_ORDER
{
EBO_LITTLE_ENDIAN,
EBO_BIG_ENDIAN,
};
CBinarySerializer()
{
m_eByteOrder = EBO_BIG_ENDIAN;
}
virtual ~CBinarySerializer() = default;
virtual bool Serialize()
{
return Serialize2Buffer(true);
}
virtual bool Deserialize()
{
return Serialize2Buffer(false);
}
virtual bool Serialize2Buffer(bool bIsSerialize)
{
return false;
}
std::vector<uint8_t> GetBuffer() const
{
return m_vecBuffer;
}
void SetByteOrder(E_BYTE_ORDER eByteOrder)
{
m_eByteOrder = eByteOrder;
}
bool IsLittleEndian() const
{
return m_eByteOrder == EBO_LITTLE_ENDIAN;
}
void ClearBuffer()
{
m_vecBuffer.clear();
}
virtual size_t GetSize() const
{
return 0;
}
std::vector<uint8_t> m_vecBuffer;
E_BYTE_ORDER m_eByteOrder;
};
三、 定义部分类型序列化的实现类
class CBinaryImplement
{
public:
static bool UCharToBuffer(std::vector<uint8_t>& vecBuffer, uint8_t u8Value)
{
vecBuffer.push_back(u8Value);
return true;
}
static bool BufferToUChar(std::vector<uint8_t>& vecBuffer, uint8_t& u8Value)
{
if (vecBuffer.size() < 1)
{
return false;
}
u8Value = vecBuffer.front();
vecBuffer.erase(vecBuffer.begin());
return true;
}
static void UShortToBuffer(std::vector<uint8_t>& vecBuffer, uint16_t u16Value, CBinarySerializer::E_BYTE_ORDER eByteOrder)
{
if (eByteOrder == CBinarySerializer::EBO_LITTLE_ENDIAN)
{
vecBuffer.push_back(u16Value & 0xFF);
vecBuffer.push_back((u16Value >> 8) & 0xFF);
}
else
{
vecBuffer.push_back((u16Value >> 8) & 0xFF);
vecBuffer.push_back(u16Value & 0xFF);
}
}
static bool BufferToUShort(std::vector<uint8_t>& vecBuffer, uint16_t& u16Value, CBinarySerializer::E_BYTE_ORDER eByteOrder)
{
if (vecBuffer.size() < 2)
{
return false;
}
if (eByteOrder == CBinarySerializer::EBO_LITTLE_ENDIAN)
{
u16Value = (vecBuffer[0] & 0xFF) | ((vecBuffer[1] & 0xFF) << 8);
}
else
{
u16Value = (vecBuffer[1] & 0xFF) | ((vecBuffer[0] & 0xFF) << 8);
}
vecBuffer.erase(vecBuffer.begin(), vecBuffer.begin() + 2);
return true;
}
static void UIntToBuffer(std::vector<uint8_t>& vecBuffer, uint32_t u32Value, CBinarySerializer::E_BYTE_ORDER eByteOrder)
{
if (eByteOrder == CBinarySerializer::EBO_LITTLE_ENDIAN)
{
vecBuffer.push_back(u32Value & 0xFF);
vecBuffer.push_back((u32Value >> 8) & 0xFF);
vecBuffer.push_back((u32Value >> 16) & 0xFF);
vecBuffer.push_back((u32Value >> 24) & 0xFF);
}
else
{
vecBuffer.push_back((u32Value >> 24) & 0xFF);
vecBuffer.push_back((u32Value >> 16) & 0xFF);
vecBuffer.push_back((u32Value >> 8) & 0xFF);
vecBuffer.push_back(u32Value & 0xFF);
}
}
static bool BufferToUInt(std::vector<uint8_t>& vecBuffer, uint32_t& u32Value, CBinarySerializer::E_BYTE_ORDER eByteOrder)
{
if (vecBuffer.size() < 4)
{
return false;
}
if (eByteOrder == CBinarySerializer::EBO_LITTLE_ENDIAN)
{
u32Value = (vecBuffer[0] & 0xFF) | ((vecBuffer[1] & 0xFF) << 8) | ((vecBuffer[2] & 0xFF) << 16) | ((vecBuffer[3] & 0xFF) << 24);
}
else
{
u32Value = (vecBuffer[3] & 0xFF) | ((vecBuffer[2] & 0xFF) << 8) | ((vecBuffer[1] & 0xFF) << 16) | ((vecBuffer[0] & 0xFF) << 24);
}
vecBuffer.erase(vecBuffer.begin(), vecBuffer.begin() + 4);
return true;
}
static void strToBuffer(std::vector<uint8_t>& vecBuffer, const std::string& strValue)
{
for (auto u8Char : strValue)
{
vecBuffer.push_back(u8Char);
}
}
/**
* @brief 将缓冲区中的数据转换为字符串
* @param vecBuffer 输入的缓冲区
* @param strValue 输出的字符串
* @param nLen 要读取的字节数,默认为-1,表示读取整个缓冲区
* @return bool 转换是否成功
*/
static bool BufferToStr(std::vector<uint8_t>& vecBuffer, std::string& strValue, size_t nLen = -1)
{
if (vecBuffer.empty() && nLen > 0)
{
return false;
}
strValue.clear();
if (nLen == -1)
{
for (auto u8Char : vecBuffer)
{
strValue.push_back(u8Char);
}
vecBuffer.clear();
}
else
{
if (vecBuffer.size() < nLen)
{
return false;
}
for (size_t i = 0; i < nLen; ++i)
{
strValue.push_back(vecBuffer[i]);
}
vecBuffer.erase(vecBuffer.begin(), vecBuffer.begin() + nLen);
}
return true;
}
static bool ObjToBuffer(std::vector<uint8_t>& vecBuffer, CBinarySerializer& obj)
{
if (!obj.Serialize2Buffer(true))
{
return false;
}
vecBuffer.insert(vecBuffer.end(), obj.m_vecBuffer.begin(), obj.m_vecBuffer.end());
return true;
}
static bool BufferToObj(std::vector<uint8_t>& vecBuffer, CBinarySerializer& obj)
{
if (vecBuffer.empty() || obj.GetSize() > vecBuffer.size())
{
return false;
}
obj.m_vecBuffer.insert(obj.m_vecBuffer.begin(), vecBuffer.begin(), vecBuffer.begin() + obj.GetSize());
if (!obj.Serialize2Buffer(false))
{
return false;
}
return true;
}
};
四、定义便以使用的Serialize2Buffer函数实现宏
#define BINARY_SERIALIZE_BEGIN_1(ClassName) \
public: \
bool Serialize2Buffer(bool bIsSerialize) override \
{
#define BINARY_SERIALIZE_UCHAR(Var) \
if (bIsSerialize) \
{ \
if (!CBinaryImplement::UCharToBuffer(m_vecBuffer, Var)) \
{ \
return false; \
} \
} \
else \
{ \
if (!CBinaryImplement::BufferToUChar(m_vecBuffer, Var)) \
{ \
return false; \
} \
}
#define BINARY_SERIALIZE_USHORT(Var) \
if (bIsSerialize) \
{ \
CBinaryImplement::UShortToBuffer(m_vecBuffer, Var, m_eByteOrder); \
} \
else \
{ \
if (!CBinaryImplement::BufferToUShort(m_vecBuffer, Var, m_eByteOrder)) \
{ \
return false; \
} \
}
#define BINARY_SERIALIZE_UINT(Var) \
if (bIsSerialize) \
{ \
CBinaryImplement::UIntToBuffer(m_vecBuffer, Var, m_eByteOrder); \
} \
else \
{ \
if (!CBinaryImplement::BufferToUInt(m_vecBuffer, Var, m_eByteOrder)) \
{ \
return false; \
} \
}
#define BINARY_SERIALIZE_STR(Var, Len) \
if (bIsSerialize) \
{ \
CBinaryImplement::strToBuffer(m_vecBuffer, Var); \
} \
else \
{ \
if (!CBinaryImplement::BufferToStr(m_vecBuffer, Var, Len)) \
{ \
return false; \
} \
}
#define BINARY_SERIALIZE_OBJ(Obj)\
if (bIsSerialize) \
{ \
if (!CBinaryImplement::ObjToBuffer(m_vecBuffer, Obj)) \
{ \
return false; \
} \
} \
else \
{ \
if (!CBinaryImplement::BufferToObj(m_vecBuffer, Obj)) \
{ \
return false; \
} \
}
#define BINARY_SERIALIZE_END_1() \
return true; \
} \
需要序列化的类中 继承 CBinarySerializer 增加宏 就可以不用单独写序列化的代码
五、动物园测试类
class CIcdBird : public CBinarySerializer
{
public:
enum E_BIRD_TYPE
{
EBT_EAGLE, // 老鹰
EBT_FLAMINGO, // 灰狼
};
size_t GetSize() const override
{
return sizeof(m_u8BirdType) + sizeof(m_u16BirdAge) + sizeof(m_u32BirdId);
}
CIcdBird() = default;
virtual ~CIcdBird() = default;
BINARY_SERIALIZE_BEGIN_1(CIcdBird)
BINARY_SERIALIZE_UCHAR(m_u8BirdType)
BINARY_SERIALIZE_USHORT(m_u16BirdAge)
BINARY_SERIALIZE_UINT(m_u32BirdId)
BINARY_SERIALIZE_END_1()
uint8_t m_u8BirdType;
uint16_t m_u16BirdAge;
uint32_t m_u32BirdId;
std::string m_strBirdName;
};
class CIcdZoo : public CBinarySerializer
{
public:
CIcdZoo() = default;
virtual ~CIcdZoo() = default;
BINARY_SERIALIZE_BEGIN_1(CIcdZoo)
BINARY_SERIALIZE_UINT(m_u32Z00Id)
BINARY_SERIALIZE_OBJ(m_iBird)
BINARY_SERIALIZE_END_1()
uint32_t m_u32Z00Id;
CIcdBird m_iBird;
};
/**
* @brief 测试二进制序列化功能
*
* 该函数用于测试二进制序列化的相关功能,包括创建和序列化鸟类和动物园对象。
*
* @return int 返回测试结果,通常为0表示成功,非0表示失败。
*/
void TestBinary()
{
CIcdBird icdBird;
icdBird.m_u8BirdType = CIcdBird::EBT_EAGLE;
icdBird.m_u16BirdAge = 3;
icdBird.m_u32BirdId = 33;
icdBird.m_strBirdName = "Eagle";
icdBird.Serialize();
std::vector<uint8_t> vecBirdBuffer = icdBird.GetBuffer();
for (auto u8BirdByte : vecBirdBuffer)
{
printf("%02X ", u8BirdByte);
}
printf("\n");
CIcdBird icdBird2;
icdBird2.m_vecBuffer = vecBirdBuffer;
icdBird2.Deserialize();
std::cout << icdBird2.m_u32BirdId << std::endl;
CIcdZoo icdZoo;
icdZoo.m_u32Z00Id = 55;
icdZoo.m_iBird = icdBird2;
icdZoo.Serialize();
vecBirdBuffer = icdZoo.GetBuffer();
for (auto u8BirdByte : vecBirdBuffer)
{
printf("%02X ", u8BirdByte);
}
printf("\n");
std::cout << icdZoo.m_u32Z00Id << std::endl;
std::cout << icdZoo.m_iBird.m_u32BirdId << std::endl;
}
CIcdBird 继承与 CBinarySerializer 增加宏后不需要额外代码就可以序列化
六、测试结果
序列化和反序列化都没有问题,继续完善类型