Qt 二进制数据读写详解

 更新时间:2026年01月05日 09:15:27   作者:小灰灰搞电子  
本文详细介绍了Qt中二进制数据读写的核心概念和操作方法,主要是QByteArray、QFile、QDataStream和QBuffer的功能及用途,具有一定的参考价值,感兴趣的可以了解一下

一、Qt 二进制数据读写讲解

1、核心概念

  1. QByteArray:这是 Qt 中处理原始字节数据的核心容器类。它可以存储任意字节序列(char* 数据)。
  2. QFile:用于访问文件系统中的文件。它可以以文本模式或二进制模式打开文件。
  3. QDataStream:提供了一种序列化的方式,将基本数据类型(如 int, float, QString 等)和更复杂的结构转换成字节流,以便写入文件或网络套接字,并能从字节流中还原出来。它负责处理字节序(Endianness)等问题。
  4. QBuffer:将 QByteArray 当作一个 QIODevice(类似于文件或套接字)来使用,方便进行流式操作。

2、二进制写入操作

2.1、方法一:直接使用QFile和QByteArray

#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进行序列化(推荐)

#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

#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进行反序列化(推荐)

#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进行内存读写

#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、注意事项

  1. 字节序:如果数据需要在不同架构(x86, ARM 等)或不同系统(Windows, Linux, macOS)间交换,务必使用 QDataStream 并统一设置字节序(通常用默认的大端序或显式设置)。
  2. 版本控制QDataStream 的序列化格式在不同 Qt 版本间可能有微小变化。使用 setVersion 指定一致的版本号(如 Qt_6_5)可以保证长期存储或跨版本程序的数据兼容性。
  3. 错误处理:始终检查文件是否成功打开、读写操作是否成功(write 返回写入字节数,QDataStream::status())。
  4. 类型匹配:读取时使用的类型必须与写入时完全匹配(例如,写入 qint32 就必须读取 qint32,不能是 int,除非你确定平台上的 int 就是 32 位)。
  5. 性能:对于大文件,考虑分块读取写入,避免一次性 readAll() 消耗过多内存。
  6. 安全性:读取外部二进制文件时要注意潜在的安全风险(如缓冲区溢出)。

6、示例:一个简单的十六进制查看器片段

#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、源码

#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;
}


代码说明:

  1. 二进制写入

    • 使用 QFileQIODevice::WriteOnly 模式创建文件
    • QDataStream 提供序列化接口
    • 通过 << 操作符写入多种数据类型
  2. 二进制读取

    • QIODevice::ReadOnly 模式打开文件
    • 使用相同的 QDataStream 版本
    • 通过 >> 操作符按写入顺序读取数据
  3. 注意事项

    • 数据流版本需保持一致(Qt_6_0 可替换为实际版本)
    • 读取顺序必须与写入顺序严格一致
    • 支持所有Qt基本类型和容器类(如 QList, QMap
  4. 数据类型支持

    • 基本类型:int, float, double, bool
    • Qt类型:QString, QByteArray, QDateTime
    • 自定义类型(需实现序列化操作符)

2、运行效果

到此这篇关于Qt 二进制数据读写详解的文章就介绍到这了,更多相关Qt 二进制数据读写内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++利用链表实现图书信息管理系统

    C++利用链表实现图书信息管理系统

    这篇文章主要为大家详细介绍了C++利用链表实现图书信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • 深入理解char *a与char a[]的区别

    深入理解char *a与char a[]的区别

    很多人可能或多或少知道char *a与char a[]的一些区别,但如果详细的说出来却不知如何说去,下面这篇文章就给大家详细介绍了关于C语言中char *a与char a[]的区别,有需要的朋友们可以参考借鉴,下面来一起学习学习吧。
    2016-12-12
  • C++ Qt QColorDialog使用方法

    C++ Qt QColorDialog使用方法

    本文主要介绍了C++ Qt QColorDialog使用方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Qt实现俄罗斯方块

    Qt实现俄罗斯方块

    这篇文章主要为大家详细介绍了Qt实现俄罗斯方块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法

    Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法

    这篇文章主要介绍了Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法,请注意代码中包含大量注释,需要的朋友可以参考下
    2014-09-09
  • C++实现猜数字游戏

    C++实现猜数字游戏

    这篇文章主要为大家详细介绍了C++实现猜数字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C语言联合体的实现示例

    C语言联合体的实现示例

    C语言联合体是一种特殊的数据结构,它允许在相同的内存位置存储不同的数据类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • C++ 超详细梳理继承的概念与使用

    C++ 超详细梳理继承的概念与使用

    这篇文章主要介绍了C++ 多继承详情,C++支持多继承,即允许一个类同时继承多个类。只有C++等少数语言支持多继承,下面我们就来看看具体的多继承介绍吧,需要的朋友可以参考一下
    2022-03-03
  • C语言实现BMP图像细化处理

    C语言实现BMP图像细化处理

    这篇文章主要为大家详细介绍了C语言实现BMP图像细化处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • C++11中的变长模板的示例详解

    C++11中的变长模板的示例详解

    C++中的变长模板真的是又臭又长,晦涩难懂,但是确实有些STL库就是这么写的。本文就来和大家聊聊C++11中这些变长模块的使用,需要的可以参考一下
    2023-02-02

最新评论