Qt之数据序列化(结构体序列化,类序列化,含源码+注释)

一、数据序列化示例图

下图包含常用类型、复杂容器、结构体、类对象的序列化和反序列化值演示。
在这里插入图片描述
提示:不会使用Qt设计师设计界面的小伙伴点击这里

二、序列化(个人理解)

  1. 序列化是什么? 通俗的说是将数据转换成另一种格式给过程,序列化出来的数据,可通过反序列化得到原本的数据,并且合理的序列化操作,可以包容各种类型的转换。
  2. 序列化的作用;当不同类型的数据需要存储在同一容器或数据表中,可通过序列化将数据转换为统一格式。
  3. Qt中自带有QDataStream类,可实现序列化操作;其中Qt自带的类型(数值型,布尔类型,各种容器类型)可以直接使用“<<”、“>>” 两个运算符做序列化和反序列化操作,不过自定义结构体和类不能直接序列化和反序列化,需要我们自己重写操作符函数才能使用(具体查看源码 SerializeType.h)。

三、部分源码讲解

序列化和反序列化流程

其中序列化和反序列化简单的操作流程如下
基本上所有序列化、反序列化流程都是如此,记住这个顺序最好

  1. 序列化(用源码中整形举例)
    // 定义整形值(数据类型可按自己意向更改)
    int val = 666;
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
    // 通过'<<'运算符将数据写入
    stream << val;
  1. 反序列化(用源码中整形举例)
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::ReadOnly);
    // 创建序列化值所对应的类型变量(如本类型转换前类型为int,接收类型也应与之对应)
    int val = 0;   // 初始化是和序列化值区分
    // 通过'>>'运算符将数据从流中读出
    stream >> val;

SerializeType.h头文件讲解

该头文件中包含学生信息结构体和学生信息类,咋一看两者内容都一样,其实是真的一样;这样是为了表达说结构体和类中序列化、反序列化操作超级像,了解一个相当于了解第二个

三、源码

SerializeType.h

#ifndef SERIALIZETYPE_H
#define SERIALIZETYPE_H

#include <QString>
#include <QtDebug>
#include <QDataStream>

// 创建学生信息结构体
struct studentStr
{
    QString id;     // 学号

    QString name;   // 学生姓名

    int age;        // 学生年龄

    QMap<QString, int> score;    // 学生成绩

    // 重写QDataStream& operator<<操作符,做数据序列化操作
    friend QDataStream& operator<<(QDataStream &stream, const studentStr &student)
    {
        // 将数据输入流对象中
        stream << student.id;
        stream << student.name;
        stream << student.age;
        stream << student.score;
        return stream;
    }

    // 重写QDataStream& operator>>操作符,做数据反序列化操作
    friend QDataStream& operator>>(QDataStream &stream, studentStr &student)
    {
        // 从流对象中输出数据到学生结构体引用中
        stream >> student.id;
        stream >> student.name;
        stream >> student.age;
        stream >> student.score;
        return stream;
    }

    // 重写QDebug operator<<函数,用作输出内容
    friend QDebug operator<<(QDebug debug, const studentStr &student)
    {
        // 向QDebug对象输入数据
        debug << "学号 " << student.id;
        debug << "\n姓名 " << student.name;
        debug << "\n年龄 " << student.age;
        foreach(QString subject, student.score.keys())
        {
            debug << "\n" + subject + " " << student.score.value(subject);
        }
            debug << "\n";
        return debug;
    }
};


// 创建学生信息类
class studentInfo
{
public:
    QString id;     // 学号

    QString name;   // 学生姓名

    int age;        // 学生年龄

    QMap<QString, int> score;    // 学生成绩

    // 重写QDataStream& operator<<操作符,做数据序列化操作
    friend QDataStream& operator<<(QDataStream &stream, const studentInfo &student)
    {
        // 将数据输入流对象中
        stream << student.id;
        stream << student.name;
        stream << student.age;
        stream << student.score;
        return stream;
    }

    // 重写QDataStream& operator>>操作符,做数据反序列化操作
    friend QDataStream& operator>>(QDataStream &stream, studentInfo &student)
    {
        // 从流对象中输出数据到学生结构体引用中
        stream >> student.id;
        stream >> student.name;
        stream >> student.age;
        stream >> student.score;
        return stream;
    }

    // 重写QDebug operator<<函数,用作输出内容
    friend QDebug operator<<(QDebug debug, const studentInfo &student)
    {
        // 向QDebug对象输入数据
        debug << "学号 " << student.id;
        debug << "\n姓名 " << student.name;
        debug << "\n年龄 " << student.age;
        foreach(QString subject, student.score.keys())
        {
            debug << "\n" + subject + " " << student.score.value(subject);
        }
        debug << "\n";
        return debug;
    }
};

#endif // SERIALIZETYPE_H

CSerializeWindow.h

#ifndef CSERIALIZEWINDOW_H
#define CSERIALIZEWINDOW_H

#include <QMainWindow>
#include <QAbstractButton>
#include <QDataStream>
#include <QMap>
#include <QDebug>


namespace Ui {
class CSerializeWindow;
}

class CSerializeWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit CSerializeWindow(QWidget *parent = nullptr);
    ~CSerializeWindow();

private slots:
    /**
     * @brief on_numSerializeBtn_clicked 数值类型序列化
     */
    void on_numSerializeBtn_clicked();

    /**
     * @brief on_numDeserializeBtn_clicked 数值类型反序列化
     */
    void on_numDeserializeBtn_clicked();

    /**
     * @brief on_containerSerializeBtn_clicked 复杂容器序列化
     */
    void on_containerSerializeBtn_clicked();

    /**
     * @brief on_containerDeserializeBtn_clicked 复杂容器反序列化
     */
    void on_containerDeserializeBtn_clicked();

    /**
     * @brief on_structSerializeBtn_clicked 自定义结构体序列化
     */
    void on_structSerializeBtn_clicked();

    /**
     * @brief on_structDeserializeBtn_clicked 自定义结构体反序列化
     */
    void on_structDeserializeBtn_clicked();

    /**
     * @brief on_classSerializeBtn_clicked 类对象序列化
     */
    void on_classSerializeBtn_clicked();

    /**
     * @brief on_classDeserializeBtn_clicked 类对象反序列化
     */
    void on_classDeserializeBtn_clicked();


    ///做按钮互斥操作
    /**
     * @brief on_serializeBtnGroup_buttonClicked 序列化按钮组点击函数
     * @param id 点击按钮id
     */
    void on_serializeBtnGroup_buttonClicked(int id);

    /**
     * @brief on_deserializeBtnGroup_buttonClicked 反序列化按钮组点击函数
     * @param btn 点击按钮对象指针
     */
    void on_deserializeBtnGroup_buttonClicked(QAbstractButton *btn);

private:
    Ui::CSerializeWindow *ui;

    QByteArray m_dataArray;
};

#endif // CSERIALIZEWINDOW_H

CSerializeWindow.cpp

#include "CSerializeWindow.h"
#include "ui_CSerializeWindow.h"

#include "SerializeType.h"
#include <QtDebug>

CSerializeWindow::CSerializeWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CSerializeWindow)
{
    ui->setupUi(this);
}

CSerializeWindow::~CSerializeWindow()
{
    delete ui;
}

void CSerializeWindow::on_numSerializeBtn_clicked()
{
    // 定义整形值(数据类型可按自己意向更改)
    int val = 666;
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
    // 通过'<<'运算符将数据写入
    stream << val;

    // 添加提示文本
    QString tips("数值:%1序列化完成");
    qDebug() << tips.arg(val);
}

void CSerializeWindow::on_numDeserializeBtn_clicked()
{
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::ReadOnly);
    // 创建序列化值所对应的类型变量(如本类型转换前类型为int,接收类型也应与之对应)
    int val = 0;   // 初始化是和序列化值区分
    // 通过'>>'运算符将数据从流中读出
    stream >> val;

    // 添加提示文本
    QString tips("数值类型反序列化完成,值为:%1");
    qDebug() << tips.arg(val) << "\n";
}

void CSerializeWindow::on_containerSerializeBtn_clicked()
{
    // 定义链表容器(数据类型可按自己意向更改)
    QList<QString> list;
    list << "123" << "456" << "789";
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
    // 通过'<<'运算符将数据写入
    stream << list;

    // 输出提示文本
    qDebug() << list << "容器序列化完成";
}

void CSerializeWindow::on_containerDeserializeBtn_clicked()
{
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::ReadOnly);
    // 创建序列化值所对应的类型变量(如本类型转换前类型为QList<QString>,接收类型也应与之对应)
    QList<QString> list = QList<QString>(); // 初始化是和序列化值区分(保证变量值最初为空)
    // 通过'>>'运算符将数据从流中读出
    stream >> list;

    // 输出提示文本
    qDebug() << "数值类型反序列化完成,值为:" << list << "\n";
}

void CSerializeWindow::on_structSerializeBtn_clicked()
{
    // 创建学生结构体对象
    struct studentStr student_s;
    // 为结构体中各变量赋值
    student_s.id = "003";
    student_s.name = "小明";
    student_s.age = 21;
    student_s.score.insert("语文", 87);
    student_s.score.insert("数学", 95);
    student_s.score.insert("英语", 75);

    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
    // 通过'<<'运算符将数据写入
    stream << student_s;

    // 输出提示信息
    qDebug() << student_s.name << "的信息结构体序列化完成";

}

void CSerializeWindow::on_structDeserializeBtn_clicked()
{
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::ReadOnly);

    // 创建反序列化的学生结构体
    struct studentStr student_s;
    // 通过'>>'运算符将数据从流中读出
    stream >> student_s;

    // 输出提示文本
    qDebug().noquote().nospace() << "结构体反序列化完成,值为:\n" << student_s;
}

void CSerializeWindow::on_classSerializeBtn_clicked()
{
    // 创建学生类对象
    studentInfo student_c;
    // 为类对象中各变量赋值
    student_c.id = "101";
    student_c.name = "小王";
    student_c.age = 22;
    student_c.score.insert("语文", 91);
    student_c.score.insert("数学", 87);
    student_c.score.insert("英语", 80);

    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
    // 通过'<<'运算符将数据写入
    stream << student_c;

    // 输出提示信息
    qDebug() << student_c.name << "的信息类序列化完成";
}

void CSerializeWindow::on_classDeserializeBtn_clicked()
{
    // 创建一个数据流对象,并设置数据容器和打开方式
    QDataStream stream(&m_dataArray, QIODevice::ReadOnly);

    // 创建接收数据的学生类对象
    studentInfo student_c;
    // 通过'>>'运算符将数据从流中读出
    stream >> student_c;

    // 输出提示文本
    qDebug().noquote().nospace() << "类信息反序列化完成,值为:\n" << student_c;
}

void CSerializeWindow::on_serializeBtnGroup_buttonClicked(int id)
{
    foreach(QAbstractButton *btn, ui->serializeBtnGroup->buttons())
    {
        btn->setEnabled(false);
    }

    ui->deserializeBtnGroup->button(id)->setEnabled(true);
}

void CSerializeWindow::on_deserializeBtnGroup_buttonClicked(QAbstractButton *btn)
{
    foreach(QAbstractButton *btn, ui->serializeBtnGroup->buttons())
    {
        btn->setEnabled(true);
    }

    btn->setEnabled(false);
}

CSerializeWindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CSerializeWindow</class>
 <widget class="QMainWindow" name="CSerializeWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>596</width>
    <height>188</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>CSerializeWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QPushButton" name="numSerializeBtn">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>数值类型序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">serializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QPushButton" name="containerSerializeBtn">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>复杂容器序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">serializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="0" column="2">
     <widget class="QPushButton" name="structSerializeBtn">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>自定义结构体序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">serializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="0" column="3">
     <widget class="QPushButton" name="classSerializeBtn">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>自定义类对象序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">serializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="numDeserializeBtn">
      <property name="enabled">
       <bool>false</bool>
      </property>
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>数值类型反序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">deserializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="containerDeserializeBtn">
      <property name="enabled">
       <bool>false</bool>
      </property>
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>复杂容器反序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">deserializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="1" column="2">
     <widget class="QPushButton" name="structDeserializeBtn">
      <property name="enabled">
       <bool>false</bool>
      </property>
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>自定义结构体反序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">deserializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
    <item row="1" column="3">
     <widget class="QPushButton" name="classDeserializeBtn">
      <property name="enabled">
       <bool>false</bool>
      </property>
      <property name="sizePolicy">
       <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="text">
       <string>自定义类对象反序列化</string>
      </property>
      <attribute name="buttonGroup">
       <string notr="true">deserializeBtnGroup</string>
      </attribute>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>596</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
 <buttongroups>
  <buttongroup name="deserializeBtnGroup"/>
  <buttongroup name="serializeBtnGroup"/>
 </buttongroups>
</ui>

总结

总的来说Qt中序列化操作已经相当于傻瓜式操作了,C++中就不存在类似于QDataStream的类或功能,需要自己实现;也许在刚刚了解序列化的时候不知道在什么场景使用,但是一遇到适合的场景,你就会发现,真香!😆
那就休息了,晚安😴…

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

  • 12
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lw向北.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值