Qt 二进制数据读写详解
- [一、Qt 二进制数据读写讲解](#一、Qt 二进制数据读写讲解)
-
- 1、核心概念
- 2、二进制写入操作
-
- [2.1、方法一:直接使用 `QFile` 和 `QByteArray`](#2.1、方法一:直接使用
QFile和QByteArray) - [2.2、方法二:使用 `QDataStream` 进行序列化(推荐)](#2.2、方法二:使用
QDataStream进行序列化(推荐))
- [2.1、方法一:直接使用 `QFile` 和 `QByteArray`](#2.1、方法一:直接使用
- 3、二进制读取操作
-
- [3.1、方法一:直接使用 `QFile` 和 `QByteArray`](#3.1、方法一:直接使用
QFile和QByteArray) - [3.2、方法二:使用 `QDataStream` 进行反序列化(推荐)](#3.2、方法二:使用
QDataStream进行反序列化(推荐))
- [3.1、方法一:直接使用 `QFile` 和 `QByteArray`](#3.1、方法一:直接使用
- [4、使用 `QBuffer` 进行内存读写](#4、使用
QBuffer进行内存读写) - 5、注意事项
- 6、示例:一个简单的十六进制查看器片段
- 二、示例
一、Qt 二进制数据读写讲解
1、核心概念
QByteArray:这是 Qt 中处理原始字节数据的核心容器类。它可以存储任意字节序列(char*数据)。QFile:用于访问文件系统中的文件。它可以以文本模式或二进制模式打开文件。QDataStream:提供了一种序列化的方式,将基本数据类型(如int,float,QString等)和更复杂的结构转换成字节流,以便写入文件或网络套接字,并能从字节流中还原出来。它负责处理字节序(Endianness)等问题。QBuffer:将QByteArray当作一个QIODevice(类似于文件或套接字)来使用,方便进行流式操作。
2、二进制写入操作
2.1、方法一:直接使用 QFile 和 QByteArray
cpp
#include <QFile>
#include <QByteArray>
// 准备要写入的二进制数据
QByteArray data;
data.append(0x01); // 写入一个字节 0x01
data.append(0x02); // 写入一个字节 0x02
// ... 可以填充任意字节
// 打开文件 (使用 QIODevice::WriteOnly 和 QIODevice::Truncate 确保清空原有内容)
QFile file("binary.dat");
if (file.open(QIODevice::WriteOnly)) {
// 将整个 QByteArray 写入文件
qint64 bytesWritten = file.write(data);
if (bytesWritten == -1) {
// 处理写入错误
}
file.close(); // 关闭文件
} else {
// 处理文件打开失败
}
2.2、方法二:使用 QDataStream 进行序列化(推荐)
cpp
#include <QFile>
#include <QDataStream>
QFile file("structured.dat");
if (file.open(QIODevice::WriteOnly)) {
QDataStream out(&file);
out.setVersion(QDataStream::Qt_6_5); // 设置序列化版本,保证兼容性
// 写入各种类型的数据
quint8 byteValue = 0xAB;
qint32 intValue = 123456;
float floatValue = 3.14159f;
QString stringValue = "Hello Binary";
out << byteValue; // 写入一个字节 (quint8)
out << intValue; // 写入一个 32 位整数
out << floatValue; // 写入一个浮点数
out << stringValue; // 写入一个字符串 (Qt 会处理其内部编码和长度)
file.close();
} else {
// 处理错误
}
QDataStream 会自动处理不同平台上可能存在的字节序问题 (大端序 Big-Endian 或小端序 Little-Endian)。默认情况下,它使用大端序。你也可以使用 out.setByteOrder(QDataStream::LittleEndian) 显式设置。
3、二进制读取操作
3.1、方法一:直接使用 QFile 和 QByteArray
cpp
#include <QFile>
#include <QByteArray>
QFile file("binary.dat");
if (file.open(QIODevice::ReadOnly)) {
// 一次性读取整个文件内容到 QByteArray
QByteArray allData = file.readAll();
file.close();
// 处理 allData
if (allData.size() >= 2) {
quint8 firstByte = static_cast<quint8>(allData.at(0)); // 读取第一个字节
quint8 secondByte = static_cast<quint8>(allData.at(1)); // 读取第二个字节
// ... 根据协议解析后续字节
}
} else {
// 处理错误
}
3.2、方法二:使用 QDataStream 进行反序列化(推荐)
cpp
#include <QFile>
#include <QDataStream>
QFile file("structured.dat");
if (file.open(QIODevice::ReadOnly)) {
QDataStream in(&file);
in.setVersion(QDataStream::Qt_6_5); // 必须与写入时使用的版本一致!
// 按写入顺序读取数据
quint8 byteValue;
qint32 intValue;
float floatValue;
QString stringValue;
in >> byteValue; // 读取一个字节
in >> intValue; // 读取一个 32 位整数
in >> floatValue; // 读取浮点数
in >> stringValue; // 读取字符串
file.close();
// 现在可以使用读取到的数据 byteValue, intValue, floatValue, stringValue
} else {
// 处理错误
}
使用 QDataStream 读取时,顺序和类型必须与写入时完全一致,否则会导致数据错乱或读取失败。QDataStream 会维护一个状态,你可以通过 in.status() 检查是否有错误发生。
4、使用 QBuffer 进行内存读写
cpp
#include <QBuffer>
#include <QDataStream>
QByteArray bufferData; // 最终数据将存储在这里
QBuffer buffer(&bufferData);
buffer.open(QIODevice::WriteOnly); // 打开 Buffer 用于写入
QDataStream out(&buffer);
out << QString("Data in Memory") << 42;
buffer.close(); // 此时 bufferData 包含了序列化后的数据
// 从 bufferData 读取
buffer.setBuffer(&bufferData); // 关联同一个 QByteArray
buffer.open(QIODevice::ReadOnly); // 打开 Buffer 用于读取
QDataStream in(&buffer);
QString str;
int num;
in >> str >> num;
buffer.close();
5、注意事项
- 字节序 :如果数据需要在不同架构(x86, ARM 等)或不同系统(Windows, Linux, macOS)间交换,务必使用
QDataStream并统一设置字节序(通常用默认的大端序或显式设置)。 - 版本控制 :
QDataStream的序列化格式在不同 Qt 版本间可能有微小变化。使用setVersion指定一致的版本号(如Qt_6_5)可以保证长期存储或跨版本程序的数据兼容性。 - 错误处理 :始终检查文件是否成功打开、读写操作是否成功(
write返回写入字节数,QDataStream::status())。 - 类型匹配 :读取时使用的类型必须与写入时完全匹配(例如,写入
qint32就必须读取qint32,不能是int,除非你确定平台上的int就是 32 位)。 - 性能 :对于大文件,考虑分块读取写入,避免一次性
readAll()消耗过多内存。 - 安全性:读取外部二进制文件时要注意潜在的安全风险(如缓冲区溢出)。
6、示例:一个简单的十六进制查看器片段
cpp
#include <QFile>
#include <QDebug>
void viewHex(const QString &filename) {
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Failed to open file";
return;
}
QByteArray data = file.read(16); // 每次读取 16 字节
while (!data.isEmpty()) {
qDebug().noquote() << data.toHex(' ').toUpper(); // 转换为十六进制字符串,空格分隔,大写
data = file.read(16);
}
file.close();
}
二、示例
1、源码
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QDataStream>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_write_clicked()
{
// 二进制数据写入
qDebug()<<"开始写入!";
QFile writeFile("data.bin");
if (!writeFile.open(QIODevice::WriteOnly)) {
qDebug() << "文件打开失败";
return ;
}
QDataStream outStream(&writeFile);
outStream.setVersion(QDataStream::Qt_6_0); // 设置数据流版本
int intValue = 42;
double doubleValue = 3.14159;
QString stringValue = "Qt二进制示例";
// 写入不同类型数据
outStream << intValue << doubleValue << stringValue;
writeFile.close();
qDebug()<<"写入成功!";
}
void MainWindow::on_read_clicked()
{
// 二进制数据读取
qDebug()<<"开始读取!";
QFile readFile("data.bin");
if (!readFile.open(QIODevice::ReadOnly)) {
qDebug() << "文件打开失败";
return;
}
QDataStream inStream(&readFile);
inStream.setVersion(QDataStream::Qt_6_0);
int readInt;
double readDouble;
QString readString;
// 按写入顺序读取数据
inStream >> readInt >> readDouble >> readString;
readFile.close();
qDebug()<<"读取成功!";
// 验证读取结果
qDebug() << "读取整数:" << readInt;
qDebug() << "读取浮点数:" << readDouble;
qDebug() << "读取字符串:" << readString;
}
代码说明:
-
二进制写入:
- 使用
QFile以QIODevice::WriteOnly模式创建文件 QDataStream提供序列化接口- 通过
<<操作符写入多种数据类型
- 使用
-
二进制读取:
- 以
QIODevice::ReadOnly模式打开文件 - 使用相同的
QDataStream版本 - 通过
>>操作符按写入顺序读取数据
- 以
-
注意事项:
- 数据流版本需保持一致(
Qt_6_0可替换为实际版本) - 读取顺序必须与写入顺序严格一致
- 支持所有Qt基本类型和容器类(如
QList,QMap)
- 数据流版本需保持一致(
-
数据类型支持:
- 基本类型:
int,float,double,bool等 - Qt类型:
QString,QByteArray,QDateTime等 - 自定义类型(需实现序列化操作符)
- 基本类型:
2、运行效果


