说明
在软件开发中,经常需要将整个类数据持久化,比如将配置类中的成员数据保存到配置文件,又或是对一些场景数据进行导出导入,这个时候就需要一个数据转换,如下图:
思路
1、使用数据流方式输出到文件。
考虑到类的类型不确定性,所以我们需要使用模板参数传入,然后将模板转为数据流。
2、从类到文件,我们分两步,先将类模板转为 hex类型,然后hex类型直接写入文件。
3、一般类不支持数据流操作,所以我们需要对我们的数据类实现操作符重载。
实现
实现代码参考QxOrm项目的序列化模块。
1 导出
类 到 hex数据:
template<class T>
inline QByteArray to_byte_array(const T &obj)
{
QByteArray ba; QString err;
QDataStream stream((& ba), QIODevice::WriteOnly);
stream << (quint32)(9438);
try { stream << obj; }
catch (const std::exception & e) { err = QString("serialization error '%ERR%'").replace("%ERR%", e.what()); }
catch (...) { err = QString("serialization error '%ERR%'").replace("%ERR%", "unknown error"); }
if (! err.isEmpty()) { qDebug("to_byte_array() : %s", qPrintable(err)); ba.clear(); }
return ba;
}
类 到 文件(使用到上面的函数)
template <class T>
inline bool to_file(const T & obj, const QString & sFileName)
{
QByteArray data = to_byte_array(obj);
QFile file(sFileName);
if (! file.open(QIODevice::WriteOnly | QIODevice::Truncate))
return false;
file.write(data);
file.close();
return true;
}
2 导入
hex数据 到 类
template <class T>
inline bool from_byte_array(T & obj, const QByteArray & data)
{
bool result = false;
if (data.isEmpty())
return false;
QDataStream stream(data);
quint32 magic = 0;
stream >> magic;
if (magic != 9438)
return false;
stream >> obj;
result = true;
return result;
}
文件 到 类(使用到上面的函数)
template <class T>
inline bool from_file(T & obj, const QString & sFileName)
{
QFile file(sFileName);
if (! file.open(QIODevice::ReadOnly))
return false;
QByteArray data = file.readAll(); file.close();
return from_byte_array(obj, data);
}
使用示例
1 数据对象设计
#include <QString>
#include <QByteArray>
#include <QDataStream>
//对象数据序列化模板类
class ExampleData
{
public:
QString str1 = "";
QString str2 = "";
int i1 = 0;
int i2 = 0;
bool b1 = 0;
bool b2 = 0;
float f1 = 0.0;
float f2 = 0.0;
QByteArray hex1;
QByteArray hex2;
//一下两个操作符重载函数必须实现,否则无法输入输出数据流
//下面重载操作符不可使得类不可继承QObject类(继承QObject后它不允许对象的赋值操作)
friend QDataStream &operator<<(QDataStream &stream, const ExampleData &d)
{
stream << d.str1<<d.i1<<d.b1<<d.f1<<d.hex1; //注意,该例子为导出变量1(实际为导出需要序列化输出保存的成员变量)
return stream;
}
friend QDataStream &operator>>(QDataStream &stream, ExampleData &d)
{
stream >> d.str2>>d.i2>>d.b2>>d.f2>>d.hex2; //注意,该例子为载入变量2(实际应与导出变量及其顺序保持一致)
return stream;
}
};
2 测试函数
#include "serialization.h"
#include <QVector>
#include <QDebug>
//序列化输出、输入测试函数
void testFunction()
{
QVector<ExampleData> dataList; //or QList、QMap、QHash
for(int i = 0;i < 12;i ++)
{
ExampleData d;
d.str1 = QString("string:%1").arg(i);
d.i1 = qrand()%100;
d.b1 = qrand()%2;
d.f1 = (qrand()%100) / 0.1;
d.hex1 = "123456789abcdefg";
dataList.append(d);
}
Serialization::to_file(dataList,QString("./testFunctionFile"));
dataList.clear();
Serialization::from_file(dataList,QString("./testFunctionFile"));
dataList.clear();
}