文章目录
一、数据序列化示例图
下图包含常用类型、复杂容器、结构体、类对象的序列化和反序列化值演示。
提示:不会使用Qt设计师设计界面的小伙伴点击这里
二、序列化(个人理解)
- 序列化是什么? 通俗的说是将数据转换成另一种格式给过程,序列化出来的数据,可通过反序列化得到原本的数据,并且合理的序列化操作,可以包容各种类型的转换。
- 序列化的作用;当不同类型的数据需要存储在同一容器或数据表中,可通过序列化将数据转换为统一格式。
- Qt中自带有QDataStream类,可实现序列化操作;其中Qt自带的类型(数值型,布尔类型,各种容器类型)可以直接使用“<<”、“>>” 两个运算符做序列化和反序列化操作,不过自定义结构体和类不能直接序列化和反序列化,需要我们自己重写操作符函数才能使用(具体查看源码 SerializeType.h)。
三、部分源码讲解
序列化和反序列化流程
其中序列化和反序列化简单的操作流程如下
基本上所有序列化、反序列化流程都是如此,记住这个顺序最好
- 序列化(用源码中整形举例)
// 定义整形值(数据类型可按自己意向更改)
int val = 666;
// 创建一个数据流对象,并设置数据容器和打开方式
QDataStream stream(&m_dataArray, QIODevice::WriteOnly);
// 通过'<<'运算符将数据写入
stream << val;
- 反序列化(用源码中整形举例)
// 创建一个数据流对象,并设置数据容器和打开方式
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^/)
注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除