奔跑的牛牛 發表於 2026-1-5 09:15:27

Qt 二进制数据读写详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、Qt 二进制数据读写讲解</li><ul class="second_class_ul"><li>1、核心概念</li><li>2、二进制写入操作</li><ul class="third_class_ul"><li>2.1、方法一:直接使用QFile和QByteArray</li><li>2.2、方法二:使用QDataStream进行序列化(推荐)</li></ul><li>3、二进制读取操作</li><ul class="third_class_ul"><li>3.1、方法一:直接使用QFile和QByteArray</li><li>3.2、方法二:使用QDataStream进行反序列化(推荐)</li></ul><li>4、使用QBuffer进行内存读写</li><ul class="third_class_ul"></ul><li>5、注意事项</li><ul class="third_class_ul"></ul><li>6、示例:一个简单的十六进制查看器片段</li><ul class="third_class_ul"></ul></ul><li>二、示例</li><ul class="second_class_ul"><li>1、源码</li><ul class="third_class_ul"></ul><li>2、运行效果</li><ul class="third_class_ul"></ul></ul></ul></div><p class="maodian"></p><h2>一、Qt 二进制数据读写讲解</h2>
<p class="maodian"></p><h3>1、核心概念</h3>
<ol><li>QByteArray:这是 Qt 中处理原始字节数据的核心容器类。它可以存储任意字节序列(char* 数据)。</li><li>QFile:用于访问文件系统中的文件。它可以以文本模式或二进制模式打开文件。</li><li>QDataStream:提供了一种序列化的方式,将基本数据类型(如 int, float, QString 等)和更复杂的结构转换成字节流,以便写入文件或网络套接字,并能从字节流中还原出来。它负责处理字节序(Endianness)等问题。</li><li>QBuffer:将 QByteArray 当作一个 QIODevice(类似于文件或套接字)来使用,方便进行流式操作。</li></ol>
<p class="maodian"></p><h3>2、二进制写入操作</h3>
<p class="maodian"></p><h4>2.1、方法一:直接使用QFile和QByteArray</h4>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QFile&gt;
#include &lt;QByteArray&gt;

// 准备要写入的二进制数据
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 {
    // 处理文件打开失败
}
</pre></div>
<p class="maodian"></p><h4>2.2、方法二:使用QDataStream进行序列化(推荐)</h4>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QFile&gt;
#include &lt;QDataStream&gt;

QFile file("structured.dat");
if (file.open(QIODevice::WriteOnly)) {
    QDataStream out(&amp;file);
    out.setVersion(QDataStream::Qt_6_5); // 设置序列化版本,保证兼容性

    // 写入各种类型的数据
    quint8 byteValue = 0xAB;
    qint32 intValue = 123456;
    float floatValue = 3.14159f;
    QString stringValue = "Hello Binary";

    out &lt;&lt; byteValue; // 写入一个字节 (quint8)
    out &lt;&lt; intValue;// 写入一个 32 位整数
    out &lt;&lt; floatValue; // 写入一个浮点数
    out &lt;&lt; stringValue; // 写入一个字符串 (Qt 会处理其内部编码和长度)

    file.close();
} else {
    // 处理错误
}
</pre></div>
<p><code>QDataStream</code> 会自动处理不同平台上可能存在的<strong>字节序问题</strong>(大端序 Big-Endian 或小端序 Little-Endian)。默认情况下,它使用大端序。你也可以使用 <code>out.setByteOrder(QDataStream::LittleEndian)</code> 显式设置。</p>
<p class="maodian"></p><h3>3、二进制读取操作</h3>
<p class="maodian"></p><h4>3.1、方法一:直接使用QFile和QByteArray</h4>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QFile&gt;
#include &lt;QByteArray&gt;

QFile file("binary.dat");
if (file.open(QIODevice::ReadOnly)) {
    // 一次性读取整个文件内容到 QByteArray
    QByteArray allData = file.readAll();
    file.close();

    // 处理 allData
    if (allData.size() &gt;= 2) {
      quint8 firstByte = static_cast&lt;quint8&gt;(allData.at(0)); // 读取第一个字节
      quint8 secondByte = static_cast&lt;quint8&gt;(allData.at(1)); // 读取第二个字节
      // ... 根据协议解析后续字节
    }
} else {
    // 处理错误
}
</pre></div>
<p class="maodian"></p><h4>3.2、方法二:使用QDataStream进行反序列化(推荐)</h4>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QFile&gt;
#include &lt;QDataStream&gt;

QFile file("structured.dat");
if (file.open(QIODevice::ReadOnly)) {
    QDataStream in(&amp;file);
    in.setVersion(QDataStream::Qt_6_5); // 必须与写入时使用的版本一致!

    // 按写入顺序读取数据
    quint8 byteValue;
    qint32 intValue;
    float floatValue;
    QString stringValue;

    in &gt;&gt; byteValue;   // 读取一个字节
    in &gt;&gt; intValue;    // 读取一个 32 位整数
    in &gt;&gt; floatValue;// 读取浮点数
    in &gt;&gt; stringValue; // 读取字符串

    file.close();

    // 现在可以使用读取到的数据 byteValue, intValue, floatValue, stringValue
} else {
    // 处理错误
}
</pre></div>
<p>使用 <code>QDataStream</code> 读取时,顺序和类型必须与写入时完全一致,否则会导致数据错乱或读取失败。<code>QDataStream</code> 会维护一个状态,你可以通过 <code>in.status()</code> 检查是否有错误发生。</p>
<p class="maodian"></p><h3>4、使用QBuffer进行内存读写</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QBuffer&gt;
#include &lt;QDataStream&gt;

QByteArray bufferData; // 最终数据将存储在这里
QBuffer buffer(&amp;bufferData);
buffer.open(QIODevice::WriteOnly); // 打开 Buffer 用于写入

QDataStream out(&amp;buffer);
out &lt;&lt; QString("Data in Memory") &lt;&lt; 42;
buffer.close(); // 此时 bufferData 包含了序列化后的数据

// 从 bufferData 读取
buffer.setBuffer(&amp;bufferData); // 关联同一个 QByteArray
buffer.open(QIODevice::ReadOnly); // 打开 Buffer 用于读取

QDataStream in(&amp;buffer);
QString str;
int num;
in &gt;&gt; str &gt;&gt; num;

buffer.close();
</pre></div>
<p class="maodian"></p><h3>5、注意事项</h3>
<ol><li><strong>字节序</strong>:如果数据需要在不同架构(x86, ARM 等)或不同系统(Windows, Linux, macOS)间交换,务必使用 <code>QDataStream</code> 并统一设置字节序(通常用默认的大端序或显式设置)。</li><li><strong>版本控制</strong>:<code>QDataStream</code> 的序列化格式在不同 Qt 版本间可能有微小变化。使用 <code>setVersion</code> 指定一致的版本号(如 <code>Qt_6_5</code>)可以保证长期存储或跨版本程序的数据兼容性。</li><li><strong>错误处理</strong>:始终检查文件是否成功打开、读写操作是否成功(<code>write</code> 返回写入字节数,<code>QDataStream::status()</code>)。</li><li><strong>类型匹配</strong>:读取时使用的类型必须与写入时完全匹配(例如,写入 <code>qint32</code> 就必须读取 <code>qint32</code>,不能是 <code>int</code>,除非你确定平台上的 <code>int</code> 就是 32 位)。</li><li><strong>性能</strong>:对于大文件,考虑分块读取写入,避免一次性 <code>readAll()</code> 消耗过多内存。</li><li><strong>安全性</strong>:读取外部二进制文件时要注意潜在的安全风险(如缓冲区溢出)。</li></ol>
<p class="maodian"></p><h3>6、示例:一个简单的十六进制查看器片段</h3>
<div class="jb51code"><pre class="brush:cpp;">#include &lt;QFile&gt;
#include &lt;QDebug&gt;

void viewHex(const QString &amp;filename) {
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly)) {
      qDebug() &lt;&lt; "Failed to open file";
      return;
    }

    QByteArray data = file.read(16); // 每次读取 16 字节
    while (!data.isEmpty()) {
      qDebug().noquote() &lt;&lt; data.toHex(' ').toUpper(); // 转换为十六进制字符串,空格分隔,大写
      data = file.read(16);
    }

    file.close();
}
</pre></div>
<p class="maodian"></p><h2>二、示例</h2>
<p class="maodian"></p><h3>1、源码</h3>
<div class="jb51code"><pre class="brush:cpp;">#include "mainwindow.h"
#include "ui_mainwindow.h"
#include &lt;QFile&gt;
#include &lt;QDataStream&gt;
#include &lt;QDebug&gt;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui-&gt;setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_write_clicked()
{
    // 二进制数据写入
    qDebug()&lt;&lt;"开始写入!";
    QFile writeFile("data.bin");
    if (!writeFile.open(QIODevice::WriteOnly)) {
      qDebug() &lt;&lt; "文件打开失败";
      return ;
    }

    QDataStream outStream(&amp;writeFile);
    outStream.setVersion(QDataStream::Qt_6_0); // 设置数据流版本

    int intValue = 42;
    double doubleValue = 3.14159;
    QString stringValue = "Qt二进制示例";

    // 写入不同类型数据
    outStream &lt;&lt; intValue &lt;&lt; doubleValue &lt;&lt; stringValue;
    writeFile.close();

    qDebug()&lt;&lt;"写入成功!";
}


void MainWindow::on_read_clicked()
{
    // 二进制数据读取
    qDebug()&lt;&lt;"开始读取!";
    QFile readFile("data.bin");
    if (!readFile.open(QIODevice::ReadOnly)) {
      qDebug() &lt;&lt; "文件打开失败";
      return;
    }
    QDataStream inStream(&amp;readFile);
    inStream.setVersion(QDataStream::Qt_6_0);

    int readInt;
    double readDouble;
    QString readString;

    // 按写入顺序读取数据
    inStream &gt;&gt; readInt &gt;&gt; readDouble &gt;&gt; readString;
    readFile.close();
    qDebug()&lt;&lt;"读取成功!";
    // 验证读取结果
    qDebug() &lt;&lt; "读取整数:" &lt;&lt; readInt;
    qDebug() &lt;&lt; "读取浮点数:" &lt;&lt; readDouble;
    qDebug() &lt;&lt; "读取字符串:" &lt;&lt; readString;
}


</pre></div>
<p><strong>代码说明:</strong></p>
<ol><li><p><strong>二进制写入</strong>:</p>
<ul><li>使用 <code>QFile</code> 以 <code>QIODevice::WriteOnly</code> 模式创建文件</li><li><code>QDataStream</code> 提供序列化接口</li><li>通过 <code>&lt;&lt;</code> 操作符写入多种数据类型</li></ul></li><li><p><strong>二进制读取</strong>:</p>
<ul><li>以 <code>QIODevice::ReadOnly</code> 模式打开文件</li><li>使用相同的 <code>QDataStream</code> 版本</li><li>通过 <code>&gt;&gt;</code> 操作符按写入顺序读取数据</li></ul></li><li><p><strong>注意事项</strong>:</p>
<ul><li>数据流版本需保持一致(<code>Qt_6_0</code> 可替换为实际版本)</li><li>读取顺序必须与写入顺序严格一致</li><li>支持所有Qt基本类型和容器类(如 <code>QList</code>, <code>QMap</code>)</li></ul></li><li><p><strong>数据类型支持</strong>:</p>
<ul><li>基本类型:<code>int</code>, <code>float</code>, <code>double</code>, <code>bool</code> 等</li><li>Qt类型:<code>QString</code>, <code>QByteArray</code>, <code>QDateTime</code> 等</li><li>自定义类型(需实现序列化操作符)</li></ul></li></ol>
<p class="maodian"></p><h3>2、运行效果</h3>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010509151443.gif" /></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010509151417.png" /></p>
<p>到此这篇关于Qt 二进制数据读写详解的文章就介绍到这了,更多相关Qt 二进制数据读写内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>QT中QDataStream二进制数据读写的实现</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Qt 二进制数据读写详解