对象如何保存到文件?深入Qt序列化机制,掌握跨平台数据持久化的核心技巧
一、序列化概述
序列化是将对象状态转换为可存储或传输格式的过程,反序列化则是从存储格式还原对象。Qt提供了完整的序列化框架,支持二进制和文本两种格式。
1.1 Qt序列化核心类
| 类名 | 格式 | 特点 | 适用场景 |
|---|---|---|---|
| QDataStream | 二进制 | 高效、跨平台 | 本地存储、网络传输 |
| QTextStream | 文本 | 可读性好 | 配置文件、日志 |
| QJsonObject | JSON | 通用格式 | Web交互、配置 |
| QXmlStreamWriter | XML | 标准格式 | 数据交换 |
1.2 源码位置
qtbase/src/corelib/serialization/
├── qdatastream.cpp/h # 二进制流
├── qtextstream.cpp/h # 文本流
├── qjsondocument.cpp/h # JSON文档
├── qjsonobject.cpp/h # JSON对象
├── qxmlstream.cpp/h # XML流
└── qcborvalue.cpp/h # CBOR格式
二、QDataStream二进制序列化
2.1 基本类型序列化
cpp
#include <QDataStream>
#include <QFile>
// 写入基本类型
void writeBasicTypes()
{
QFile file("data.bin");
if (!file.open(QIODevice::WriteOnly)) return;
QDataStream out(&file);
// 设置版本(确保跨版本兼容)
out.setVersion(QDataStream::Qt_6_0);
// 写入各种类型
out << 42; // int
out << 3.14159; // double
out << true; // bool
out << QString("Hello Qt"); // QString
out << QByteArray("Binary"); // QByteArray
file.close();
}
// 读取基本类型
void readBasicTypes()
{
QFile file("data.bin");
if (!file.open(QIODevice::ReadOnly)) return;
QDataStream in(&file);
in.setVersion(QDataStream::Qt_6_0);
int i;
double d;
bool b;
QString s;
QByteArray ba;
in >> i >> d >> b >> s >> ba;
qDebug() << i << d << b << s << ba;
file.close();
}
2.2 自定义对象序列化
cpp
// 定义自定义类
class User
{
public:
QString name;
int age;
QString email;
QList<QString> tags;
// 序列化方法
friend QDataStream& operator<<(QDataStream& out, const User& user)
{
out << user.name;
out << user.age;
out << user.email;
out << user.tags;
return out;
}
// 反序列化方法
friend QDataStream& operator>>(QDataStream& in, User& user)
{
in >> user.name;
in >> user.age;
in >> user.email;
in >> user.tags;
return in;
}
};
// 使用
void saveUser()
{
User user;
user.name = "张三";
user.age = 28;
user.email = "zhangsan@example.com";
user.tags = {"Qt", "C++", "Python"};
QFile file("user.bin");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_6_0);
out << user;
file.close();
}
void loadUser()
{
User user;
QFile file("user.bin");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in.setVersion(QDataStream::Qt_6_0);
in >> user;
file.close();
qDebug() << user.name << user.age << user.email << user.tags;
}
2.3 容器序列化
cpp
// Qt容器自动支持序列化
void serializeContainers()
{
QFile file("containers.bin");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_6_0);
// QList
QList<int> intList = {1, 2, 3, 4, 5};
out << intList;
// QMap
QMap<QString, int> scoreMap;
scoreMap["Alice"] = 95;
scoreMap["Bob"] = 87;
out << scoreMap;
// QHash
QHash<QString, QString> cityMap;
cityMap["Beijing"] = "北京";
cityMap["Shanghai"] = "上海";
out << cityMap;
// 嵌套容器
QList<QMap<QString, int>> complexData;
complexData.append(scoreMap);
out << complexData;
file.close();
}
2.4 版本兼容性
cpp
// 使用版本号确保向后兼容
class Config
{
public:
int version = 2; // 当前版本
QString name;
int value;
QString description; // v2新增字段
friend QDataStream& operator<<(QDataStream& out, const Config& c)
{
out << c.version;
out << c.name;
out << c.value;
out << c.description;
return out;
}
friend QDataStream& operator>>(QDataStream& in, Config& c)
{
in >> c.version;
in >> c.name;
in >> c.value;
// 根据版本判断是否读取新字段
if (c.version >= 2) {
in >> c.description;
} else {
c.description = ""; // 默认值
}
return in;
}
};
三、JSON序列化
3.1 基本JSON操作
cpp
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
void writeJson()
{
// 创建JSON对象
QJsonObject root;
root["name"] = "张三";
root["age"] = 28;
root["active"] = true;
// 嵌套对象
QJsonObject address;
address["city"] = "北京";
address["street"] = "朝阳路";
root["address"] = address;
// 数组
QJsonArray tags;
tags.append("Qt");
tags.append("C++");
root["tags"] = tags;
// 写入文件
QJsonDocument doc(root);
QFile file("config.json");
file.open(QIODevice::WriteOnly);
file.write(doc.toJson(QJsonDocument::Indented));
file.close();
}
void readJson()
{
QFile file("config.json");
file.open(QIODevice::ReadOnly);
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject root = doc.object();
QString name = root["name"].toString();
int age = root["age"].toInt();
bool active = root["active"].toBool();
QJsonObject address = root["address"].toObject();
QString city = address["city"].toString();
QJsonArray tags = root["tags"].toArray();
for (const QJsonValue &tag : tags) {
qDebug() << tag.toString();
}
file.close();
}
3.2 自定义对象JSON序列化
cpp
class User
{
public:
QString name;
int age;
QList<QString> tags;
QJsonObject toJson() const
{
QJsonObject obj;
obj["name"] = name;
obj["age"] = age;
QJsonArray tagsArray;
for (const QString &tag : tags) {
tagsArray.append(tag);
}
obj["tags"] = tagsArray;
return obj;
}
static User fromJson(const QJsonObject &obj)
{
User user;
user.name = obj["name"].toString();
user.age = obj["age"].toInt();
QJsonArray tagsArray = obj["tags"].toArray();
for (const QJsonValue &tag : tagsArray) {
user.tags.append(tag.toString());
}
return user;
}
};
四、QSettings配置持久化
4.1 基本使用
cpp
#include <QSettings>
void saveSettings()
{
QSettings settings("MyCompany", "MyApp");
settings.setValue("window/size", QSize(800, 600));
settings.setValue("window/position", QPoint(100, 100));
settings.setValue("user/name", "张三");
settings.setValue("user/remember", true);
settings.setValue("recent/files", QStringList() << "file1.txt" << "file2.txt");
}
void loadSettings()
{
QSettings settings("MyCompany", "MyApp");
QSize size = settings.value("window/size").toSize();
QPoint pos = settings.value("window/position").toPoint();
QString name = settings.value("user/name").toString();
bool remember = settings.value("user/remember", false).toBool(); // 默认值
QStringList recent = settings.value("recent/files").toStringList();
}
4.2 自定义格式
cpp
// 使用INI格式
QSettings settings("config.ini", QSettings::IniFormat);
settings.setValue("General/Language", "zh_CN");
settings.setValue("General/Theme", "Dark");
// 使用注册表(Windows)
QSettings settings("HKEY_CURRENT_USER\Software\MyApp", QSettings::NativeFormat);
五、性能优化
5.1 批量序列化
cpp
// 使用事务提高性能
void batchSerialize(const QList<User> &users)
{
QFile file("users.bin");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_6_0);
// 先写入数量
out << users.size();
// 批量写入
for (const User &user : users) {
out << user;
}
file.close();
}
5.2 压缩序列化数据
cpp
#include <QBuffer>
#include <QByteArray>
#include <zlib.h>
QByteArray compressData(const QByteArray &data)
{
QByteArray compressed;
compressed.resize(data.size() + data.size() / 100 + 12);
uLongf destLen = compressed.size();
compress2((Bytef*)compressed.data(), &destLen,
(const Bytef*)data.constData(), data.size(),
Z_BEST_COMPRESSION);
compressed.resize(destLen);
return compressed;
}
六、总结
Qt序列化核心要点:
- QDataStream:高效的二进制序列化,支持版本兼容
- QJsonObject:通用的JSON序列化,适合Web交互
- QSettings:轻量级配置持久化
- 版本控制:使用版本号确保向后兼容
《注:若有发现问题欢迎大家提出来纠正》