QDataStream 类用于将二进制数据到 QIODevice 的序列化。
// QFile file("file.dat");
// file.open(QIODevice::WriteOnly);
// QDataStream out(&file); // 将数据序列化到文件中
// out << QString("the answer is"); // 序列化一个字符串
// out << (qint32)42; // 序列化一个整数
// file.close();
QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file); // 从文件中读取序列化的数据
QString str;
qint32 a;
in >> str >> a;
file.close();
qDebug()<<"str = "<
写入流的每个项目都以预定义的二进制格式写入,该格式因项目的类型而异。支持的 Qt 类型包括 QBrush、QColor、QDateTime、QFont、QPixmap、QString、QVariant 等。
对于整数,最好转换为 Qt 整数类型(如 qint32)以进行写入,并且读取时使用相同的 Qt 整数类型。这可确保获得所需大小的整数,并不被受编译器和平台差异所影响。
1.1、版本控制
QDataStream 的二进制格式自 Qt 1.0 以来一直在发展,并且可能会继续发展以反映 Qt 中所做的更改。 在输入或输出复杂类型时,确保读取和写入使用相同版本的流非常重要。如果需要向前和向后兼容,可以在应用程序中硬编码版本号:
stream.setVersion(QDataStream::Qt_4_0);
如果要生成新的二进制数据格式,例如由应用程序创建的文档的文件格式,可以使用 QDataStream 以可移植格式写入数据。通常,包括一个简短的标题,其中包含一个魔法数字字符串和一个版本号,以便为自己留出未来扩展的空间。 例如:
QFile file("file.xxx");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
// 一个带有“魔法数字”和版本的标题
out << (quint32)0xA0B0C0D0;
out << (qint32)123;
out.setVersion(QDataStream::Qt_4_0);
// 写入数据out << lots_of_interesting_data;
读入:
QFile file("file.xxx");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
// 读取并检查标题
quint32 magic;
in >> magic;
if (magic != 0xA0B0C0D0)
return XXX_BAD_FILE_FORMAT;
qint32 version;
in >> version;
if (version < 100)
return XXX_BAD_FILE_TOO_OLD;
if (version > 123)
return XXX_BAD_FILE_TOO_NEW;
if (version <= 110)
in.setVersion(QDataStream::Qt_3_2);
else
in.setVersion(QDataStream::Qt_4_0);
in >> lots_of_interesting_data;
if (version >= 120)
in >> data_new_in_XXX_version_1_2;
in >> other_interesting_data;
1.2、读写 Qt 集合类
Qt 容器类也可以序列化为 QDataStream。包括 QList、QSet、QHash 和 QMap。
1.3、使用读取事务
当 QDataStream 在异步设备上运行时,数据块可以在任意时间点到达。QDataStream 类实现了一种事务机制,该机制提供了使用一系列流操作符以原子方式读取数据的能力。例如,可以通过使用连接到 readyRead() 信号的槽中的事务来处理来自套接字的不完整读取:
in.startTransaction();
QString str;
qint32 a;
in >> str >> a; // 尝试以原子方式读取数据包
if (!in.commitTransaction())
return; // 等待更多数据
如果没有收到完整的数据包,此代码会将流恢复到初始位置,之后需要等待更多数据到达。
二、类型成员
1、enum QDataStream::ByteOrder:用于读取/写入数据的字节顺序。
- BigEndian:最高有效字节在前(默认)
- LittleEndian:最低有效字节在前
2、enum QDataStream::FloatingPointPrecision:用于读取/写入数据的浮点数的精度。
(在写入数据流的对象和读取数据流的对象上,浮点精度必须设置为相同的值)
- SinglePrecision:数据流中的所有浮点数都具有 32 位精度。
- DoublePrecision:数据流中的所有浮点数都具有 64 位精度。
3、enum QDataStream::Status:数据流的当前状态。
- Ok:数据流运行正常。
- ReadPastEnd:数据流已读取到底层设备中数据的末尾。
- ReadCorruptData:数据流已读取损坏数据。
- WriteFailed:数据流无法写入底层设备。
4、enum QDataStream::Version:数据序列化格式版本号。
值略。
三、成员函数
1、QDataStream(const QByteArray &a)
构造一个对字节数组 a 进行操作的只读数据流。
由于 QByteArray 不是 QIODevice 子类,因此在内部创建了 QBuffer 来包装字节数组。
QDataStream(QByteArray *a, QIODeviceBase::OpenMode mode)
构造一个对字节数组 a 进行操作的数据流。mode 描述了设备的使用方式。
QDataStream(QIODevice *d)
构造一个使用 I/O 设备的数据流。
2、void abortTransaction()
中止读取事务。通常用于在更高级别的协议错误或流同步丢失后丢弃事务。
bool commitTransaction()
完成一个读事务。返回在事务期间是否发生读取错误。
void rollbackTransaction()
恢复读取事务。当在提交事务之前检测到不完整的读取时,此函数通常用于回滚事务。
void startTransaction()
在流上启动新的读取事务。
定义读操作序列中的可恢复点。对于顺序设备,读取数据将在内部复制,以便在读取不完整的情况下进行恢复。对于随机访问设备,此函数保存流的当前位置。
3、bool atEnd()
如果 I/O 设备已到达结束位置(流或文件的结尾)或没有设置 I/O 设备,则返回 true;否则返回false。
4、QIODevice *device() / void setDevice(QIODevice *d)
当前设置的 I/O 设备。
5、QDataStream & readBytes(char *&s, uint & len)
从流中读取缓冲区 len 个字符存到 s 并返回对流的引用。
如果读取的字符串为空,则将 l 设置为 0,将 s 设置为 nullptr。
6、int readRawData(char *s, int len)
从流中最多读取 len 个字节到 s 中,并返回读取的字节数。如果发生错误,则返回 -1。
缓冲区 s 必须预先分配。
7、void resetStatus()
重置数据流的状态。
8、int skipRawData(int len)
从设备跳过 len 个字节。返回实际跳过的字节数,或 -1 表示出错。
9、QDataStream & writeBytes(const char *s, uint len)
将 s 中的 len 个字节写入流。返回对流的引用。
10、int writeRawData(const char *s, int len)
将 s 中的 len 个字节写入流。返回实际写入的字节数,错误时返回 -1。