一、概念
序列化:将对象或数据结构转换为二进制序列
反序列化:二进制序列转换为对象或数据结构
二,作用
序列化可以使对象或数据结构更方便地在网络上传输或者保存在本地文件中,反序列化可以快速地复原原有对象和数据结构,方便使用。你总不可能一个字节一个字节的输入吧。
三,用法
构造函数
QDataStream()
QDataStream(QIODevice *d)
QDataStream(QByteArray *a, QIODevice::OpenMode mode)
QDataStream(const QByteArray &a)
指定设备
设置:void setDevice(QIODevice *d)
获取:QIODevice *device() const
使用 QDataStream 时总得绑定一个 QIODevice 设备,来表明这是为哪个设备服务的。用构造函数可以指定,也可以用 setDevice() 函数指定。
关于后两个构造函数,虽然 QByteArray 类并不是 QIODevice 类的子类,但是感性上我们可以把 QByteArray a 当成一个设备。为什么这样的假定是合理的?因为 Qt 在内部已经使用 QBuffer 这个设备包装了 QByteArray,可以看源码来证实,如下图:
四,示例
值得注意的是,QT大部分原生数据类型可以直接操作,用户自定义类型需要重载<<与>>。
无需重载的情况:
// QT基础数据类型
// QT基础数据类型
QString param1 = "ABC";
int param2 = -1234;
uint param3 = 5678;
double param4 = 123.456;
// QT容器
QMap<QString, int> map;
data.map["one"] = 1;
data.map["two"] = 2;
data.map["three "] = 3;
data.map.insert("four", 4);
//写
QFile writeFile(QApplication::applicationDirPath() +"/test.dat");
writeFile.open(QIODevice::WriteOnly);
QDataStream out(&writeFile);
out << param1 << param2 << param3 << param4;
out << map;
writeFile.close();
//读
QFile readFile(QApplication::applicationDirPath() +"/test.dat");
readFile.open(QIODevice::ReadOnly);
QDataStream in(&readFile);
in >> param1 >> param2 >> param3 >> param4;
in >> map;
readFile.close();
//结构体///
typedef struct __ProjectData
{
QString str;
QMap<QString, int> map;
} ProjectData;
ProjectData data;
//重载序列化和反序列化
在h文件中需要加inline
// 重载序列化
QDataStream & operator<< (QDataStream& stream, const ProjectData& data){
stream << data.str;
stream << data.map;
return stream;
}
// 重载反序列化
QDataStream & operator>> (QDataStream& stream, ProjectData& data) {
stream>>data.str;
stream>>data.map;
return stream;
}
//顺便重载qDebug()的实现自定义类型的打印
QDebug operator<<(QDebug dbg, const ProjectData &data)
{
dbg.nospace() << "ProjectData()";
dbg.nospace() << "str(" << data.str << ")";
dbg.nospace() << "map(" << data.map << " ...)";
return dbg.maybeSpace();
}
//写
QFile writeFile(QApplication::applicationDirPath() +"/test.dat");
writeFile.open(QIODevice::WriteOnly);
QDataStream out(&writeFile);
out << data;
qDebug()<<data;
writeFile.close();
//读
QFile readFile(QApplication::applicationDirPath() +"/test.dat");
readFile.open(QIODevice::ReadOnly);
QDataStream in(&readFile);
in >> data;
qDebug()<<data;
readFile.close();
//类//
class CData
{
public:
CData(){};
QString str;
QMap<QString, int> map;
// 序列化
friend QDataStream & operator<< (QDataStream& stream, const CData& data){
stream << data.str;
stream << data.map;
return stream;
}
// 反序列化
friend QDataStream & operator>> (QDataStream& stream, CData& data) {
stream>>data.str;
stream>>data.map;
return stream;
}
// 支持qDebug
friend QDebug operator<<(QDebug dbg, const CData &data)
{
dbg.nospace() << "CData()";
dbg.nospace() << "str(" << data.str << ")";
dbg.nospace() << "map(" << data.map << " ...)";
return dbg.maybeSpace();
}
};
CData cdata;
//写
QFile writeFile(QApplication::applicationDirPath() +"/test.dat");
writeFile.open(QIODevice::WriteOnly);
QDataStream out(&writeFile);
out << cdata;
qDebug()<<cdata;
writeFile.close();
//读
QFile readFile(QApplication::applicationDirPath() +"/test.dat");
readFile.open(QIODevice::ReadOnly);
QDataStream in(&readFile);
in >> cdata
qDebug()<<cdata;;
readFile.close();
五、事务
通过事务机制可以在流上执行一次完整的流读取,如果读取出错,不会破坏原有的流状态。再重新执行一次事务即可恢复。这简化了异步操作。不需要进行额外的出错检查。
QDataStream in(&writeFile);
in.startTransaction();
// ……
if(true == in.commitTransaction()) {
}