小麻雀的春天 發表於 2025-12-14 14:39:35

Qt中QByteArray​类型的使用详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、核心定位</li><li>二、基础操作:构造与赋值</li><ul class="second_class_ul"><li>1. 空对象</li><li>2. 从C风格字符串构造</li><li>3. 从QString转换(编码敏感)</li><li>4. 填充重复字符</li><li>5. 静态工厂方法(常用)</li></ul><li>三、数据访问:读写与遍历</li><ul class="second_class_ul"><li>1. 下标访问</li><li>2. 原始指针访问</li><li>3. 遍历字节</li></ul><li>四、容量与内存管理</li><ul class="second_class_ul"><li>1. 容量查询</li><li>2. 预分配内存</li><li>3. 收缩内存</li><li>4. 清空数据</li></ul><li>五、修改操作:增删改查</li><ul class="second_class_ul"><li>1. 追加(Append)</li><li>2. 插入(Insert)</li><li>3. 删除(Remove)</li><li>4. 替换(Replace)</li><li>5. 子串提取</li></ul><li>六、查找与比较</li><ul class="second_class_ul"><li>1. 查找</li><li>2. 比较</li></ul><li>七、编码与转换</li><ul class="second_class_ul"><li>1. 转为十六进制字符串</li><li>2. 从十六进制字符串还原</li><li>3. 数字与字节序列转换</li></ul><li>八、与QString的关键区别</li><ul class="second_class_ul"></ul><li>九、在流媒体开发中的典型应用</li><ul class="second_class_ul"></ul><li>十、注意事项</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p>在Qt开发中,<code>QByteArray</code>​ 是处理<strong>原始字节数据</strong>(Raw Bytes)、<strong>8位字符串</strong>(如ASCII/Latin-1/UTF-8)和<strong>二进制 payload</strong>​ 的核心容器类。它类似C++的<code>std::vector&lt;char&gt;</code>或C风格字符串,但提供了更安全、更便捷的API,且与Qt生态(如<code>QString</code>、网络模块、文件IO)深度集成。</p>
<p class="maodian"></p><h2>一、核心定位</h2>
<p><code>QByteArray</code>的设计目标是:</p>
<ul><li>存储<strong>无编码的二进制数据</strong>(如图像像素、RTP payload、加密数据);</li><li>处理<strong>8位编码的字符串</strong>(如HTTP头部的ASCII文本、RTSP协议的UTF-8 URL);</li><li>替代C风格的<code>char[]</code>,避免手动内存管理和越界风险。</li></ul>
<p class="maodian"></p><h2>二、基础操作:构造与赋值</h2>
<p><code>QByteArray</code>支持多种初始化方式,覆盖常见场景:</p>
<p class="maodian"></p><h3>1. 空对象</h3>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba; // 空字节序列,size=0</pre></div>
<p class="maodian"></p><h3>2. 从C风格字符串构造</h3>
<div class="jb51code"><pre class="brush:cpp;">const char* cstr = "Hello, Qt!";
QByteArray ba(cstr); // 内容:"Hello, Qt!"(自动添加'\0'?不,QByteArray不强制以'\0'结尾,除非显式包含)</pre></div>
<p class="maodian"></p><h3>3. 从QString转换(编码敏感)</h3>
<p>需指定编码(如UTF-8/Latin1),将Unicode字符串转为字节序列:</p>
<div class="jb51code"><pre class="brush:cpp;">QString str = "你好,Qt!";
QByteArray utf8Ba = str.toUtf8();    // UTF-8编码的字节序列
QByteArray latin1Ba = str.toLatin1();// Latin1编码(每个字符1字节)</pre></div>
<p>反向转换(字节序列&rarr;<code>QString</code>):</p>
<div class="jb51code"><pre class="brush:cpp;">QString fromUtf8 = QString::fromUtf8(utf8Ba);   // 转回Unicode字符串
QString fromLatin1 = QString::fromLatin1(latin1Ba);</pre></div>
<p class="maodian"></p><h3>4. 填充重复字符</h3>
<div class="jb51code"><pre class="brush:cpp;">QByteArray filledBa = QByteArray::fromRawData("ABCD", 4); // 从原始数据创建(不复制)
filledBa.fill('X', 3); // 修改为"XXXD"(size=4,前3个字符替换为'X')
// 或:QByteArray ba; ba.fill('Y', 5); // 创建5个'Y':"YYYYY"</pre></div>
<p class="maodian"></p><h3>5. 静态工厂方法(常用)</h3>
<p><code>fromHex()</code>:将十六进制字符串转为字节序列</p>
<div class="jb51code"><pre class="brush:cpp;">QByteArray hex = QByteArray::fromHex("48656c6c6f"); // 对应"Hello"的字节(0x48=H, 0x65=e...)</pre></div>
<p><code>fromStdString()</code>:将<code>std::string</code>转为<code>QByteArray</code></p>
<div class="jb51code"><pre class="brush:cpp;">std::string stdStr = "std::string";
QByteArray ba = QByteArray::fromStdString(stdStr);</pre></div>
<p class="maodian"></p><h2>三、数据访问:读写与遍历</h2>
<p><code>QByteArray</code>提供<strong>安全</strong>和<strong>高效</strong>的访问方式,避免越界:</p>
<p class="maodian"></p><h3>1. 下标访问</h3>
<ul><li>at(int i):只读,返回const char&amp;,越界时触发断言(Debug模式)。</li><li>operator[](int i):可读写,返回char&amp;,Debug模式下越界检查,Release模式未定义。</li></ul>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba("Hello");
char c1 = ba.at(1);    // 'e'(只读)
ba = 'h';         // 修改为"hello"</pre></div>
<p class="maodian"></p><h3>2. 原始指针访问</h3>
<ul><li><code>constData()</code>:返回<code>const char*</code>,指向内部数据(<strong>不修改</strong>)。</li><li><code>data()</code>:非const对象返回<code>char*</code>(可修改),const对象返回<code>const char*</code>。</li></ul>
<p>⚠️ 注意:若<code>QByteArray</code>修改(如<code>append</code>)导致内存重新分配,<strong>旧指针会失效</strong>!</p>
<div class="jb51code"><pre class="brush:cpp;">const char* ptr = ba.constData(); // 指向"h"
ba.append("ello");                // 内存可能重新分配
// ptr 此时可能指向无效内存!</pre></div>
<p class="maodian"></p><h3>3. 遍历字节</h3>
<div class="jb51code"><pre class="brush:cpp;">// 方式1:基于下标
for (int i = 0; i &lt; ba.size(); ++i) {
    qDebug() &lt;&lt; static_cast&lt;int&gt;(ba); // 打印每个字节的整数值
}

// 方式2:迭代器(Qt风格)
for (auto it = ba.begin(); it != ba.end(); ++it) {
    qDebug() &lt;&lt; *it;
}</pre></div>
<p class="maodian"></p><h2>四、容量与内存管理</h2>
<p><code>QByteArray</code>动态管理内存,支持预分配和收缩:</p>
<p class="maodian"></p><h3>1. 容量查询</h3>
<ul><li><code>size()</code>:当前存储的字节数。</li><li><code>isEmpty()</code>:等价于<code>size() == 0</code>,更高效。</li><li><code>capacity()</code>:当前分配的内存容量(&ge;<code>size()</code>)。</li></ul>
<p class="maodian"></p><h3>2. 预分配内存</h3>
<p>提前预留空间,避免频繁扩容:</p>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba;
ba.reserve(1024); // 预分配1024字节,后续append无需重新分配
for (int i = 0; i &lt; 1000; ++i) {
    ba.append('a');
}</pre></div>
<p class="maodian"></p><h3>3. 收缩内存</h3>
<p>若容量远大于实际大小,可释放多余内存:</p>
<div class="jb51code"><pre class="brush:cpp;">ba.resize(10);    // 缩小size到10
ba.squeeze();   // capacity变为10,释放多余内存</pre></div>
<p class="maodian"></p><h3>4. 清空数据</h3>
<div class="jb51code"><pre class="brush:cpp;">ba.clear(); // size=0,capacity不变</pre></div>
<p class="maodian"></p><h2>五、修改操作:增删改查</h2>
<p><code>QByteArray</code>提供丰富的方法处理字节序列:</p>
<p class="maodian"></p><h3>1. 追加(Append)</h3>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba("Hello");
ba.append(" World");      // "Hello World"
ba.append('!');
ba.append(QByteArray::fromHex("00FF")); // 追加两个十六进制字节:0x00, 0xFF</pre></div>
<p class="maodian"></p><h3>2. 插入(Insert)</h3>
<div class="jb51code"><pre class="brush:cpp;">ba.insert(5, ", Qt");   // 在第5位插入,变成"Hello, Qt World!"</pre></div>
<p class="maodian"></p><h3>3. 删除(Remove)</h3>
<div class="jb51code"><pre class="brush:cpp;">ba.remove(5, 4);
// 删除从第5位开始的4个字符(", Qt"),回到"Hello World!"</pre></div>
<p class="maodian"></p><h3>4. 替换(Replace)</h3>
<div class="jb51code"><pre class="brush:cpp;">ba.replace("World", "Qt");    // "Hello Qt!"
ba.replace(6, 2, "Qt");       // 从第6位替换2个字符为"Qt",同上
ba.replace('l', 'L');         // 全局替换:'Hello Qt!' → 'HeLLo Qt!'</pre></div>
<p class="maodian"></p><h3>5. 子串提取</h3>
<ul><li><code>left(int n)</code>:取前n个字节。</li><li><code>right(int n)</code>:取后n个字节。</li><li><code>mid(int pos)</code>:从pos到末尾。</li><li><code>mid(int pos, int len)</code>:从pos取len个字节。</li></ul>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba("Hello World");
QByteArray left = ba.left(5);    // "Hello"
QByteArray mid = ba.mid(6);      // "World"
QByteArray right = ba.right(6);// "World"</pre></div>
<p class="maodian"></p><h2>六、查找与比较</h2>
<p class="maodian"></p><h3>1. 查找</h3>
<ul><li><code>contains(const QByteArray&amp; str)</code>:是否包含子串。</li><li><code>indexOf(const QByteArray&amp; str)</code>:返回第一个匹配的索引(-1表示未找到)。</li><li><code>lastIndexOf(const QByteArray&amp; str)</code>:返回最后一个匹配的索引。</li><li><code>startsWith(const QByteArray&amp; prefix)</code>:是否以prefix开头。</li><li><code>endsWith(const QByteArray&amp; suffix)</code>:是否以suffix结尾。</li></ul>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba("Hello World");
bool hasHello = ba.contains("Hello"); // true
int idx = ba.indexOf("World");      // 6
bool startsWithHe = ba.startsWith("He"); // true</pre></div>
<p class="maodian"></p><h3>2. 比较</h3>
<ul><li><code>operator==</code>:内容+大小完全一致才相等。</li><li><code>operator&lt;</code>:按字典序比较(字节级)。</li><li><code>equals(const QByteArray&amp; other)</code>:等价于<code>==</code>。</li></ul>
<div class="jb51code"><pre class="brush:cpp;">QByteArray a("abc");
QByteArray b("abd");
bool equal = (a == b); // false
bool less = (a &lt; b);   // true</pre></div>
<p class="maodian"></p><h2>七、编码与转换</h2>
<p><code>QByteArray</code>常用来处理<strong>编码转换</strong>,尤其是与网络协议、文件格式交互时:</p>
<p class="maodian"></p><h3>1. 转为十六进制字符串</h3>
<div class="jb51code"><pre class="brush:cpp;">QByteArray ba("Hello");
QByteArray hex = ba.toHex(); // "48656c6c6f"(小写)
QByteArray hexUpper = ba.toHex().toUpper(); // "48656C6C6F"</pre></div>
<p class="maodian"></p><h3>2. 从十六进制字符串还原</h3>
<div class="jb51code"><pre class="brush:cpp;">QByteArray restored = QByteArray::fromHex("48656c6c6f"); // "Hello"</pre></div>
<p class="maodian"></p><h3>3. 数字与字节序列转换</h3>
<p>将数字转为字节序列(需注意<strong>字节序</strong>,网络传输用大端):</p>
<div class="jb51code"><pre class="brush:cpp;">quint32 num = 0x12345678;
// 转为大端字节序列
char* bytes = reinterpret_cast&lt;char*&gt;(&amp;num);
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
qSwap(bytes, bytes);
qSwap(bytes, bytes);
#endif
QByteArray ba(bytes, sizeof(num)); // 大端的0x12345678</pre></div>
<p>Qt提供工具函数简化字节序处理:</p>
<div class="jb51code"><pre class="brush:cpp;">quint32 num = 0x12345678;
QByteArray bigEndianBa = QByteArray::fromRawData(
    reinterpret_cast&lt;const char*&gt;(&amp;num), sizeof(num)
);
bigEndianBa = bigEndianBa.toBigEndian(); // 显式转大端(若系统是小端)</pre></div>
<p class="maodian"></p><h2>八、与QString的关键区别</h2>
<table><thead><tr><th><p>特性</p></th><th><p>QByteArray</p></th><th><p>QString</p></th></tr></thead><tbody><tr><td><p>编码</p></td><td><p>无编码/8位编码(ASCII/Latin1)</p></td><td><p>Unicode(UTF-16)</p></td></tr><tr><td><p>用途</p></td><td><p>二进制数据、8位文本</p></td><td><p>多语言文本</p></td></tr><tr><td><p>转换</p></td><td><p>需指定编码(如toUtf8())</p></td><td><p>自动处理Unicode</p></td></tr></tbody></table>
<p class="maodian"></p><h2>九、在流媒体开发中的典型应用</h2>
<p><code>QByteArray</code>是流媒体处理的&ldquo;瑞士军刀&rdquo;,常见场景:</p>
<p><strong>协议解析</strong>:解析RTSP/RTP/RTCP包的头部和负载(如提取RTP的序列号、时间戳)。</p>
<div class="jb51code"><pre class="brush:cpp;">// 解析RTP头部(12字节)
QByteArray rtpPacket = ...;
if (rtpPacket.size() &lt; 12) return;
quint8 version = rtpPacket &gt;&gt; 6; // 版本号(第0字节高2位)
quint16 seq = qFromBigEndian&lt;quint16&gt;(rtpPacket.constData() + 2); // 序列号(第2-3字节,大端)</pre></div>
<p><strong>媒体数据封装</strong>:封装H.264/H.265的NALU到RTP payload,或打包MP4 box。</p>
<p><strong>网络IO</strong>:读取UDP/TCP数据,直接存储到<code>QByteArray</code>中处理。</p>
<p><strong>元数据处理</strong>:解析MP4/FLV文件的元数据(如时长、分辨率),需处理字节级的tag结构。</p>
<p class="maodian"></p><h2>十、注意事项</h2>
<ul><li><strong>字节序</strong>:网络传输用大端(Big-Endian),本地处理需用<code>qToBigEndian</code>/<code>qFromBigEndian</code>转换。</li><li><strong>内存有效性</strong>:<code>constData()</code>/<code>data()</code>返回的指针在<code>QByteArray</code>修改后可能失效,需谨慎使用。</li><li><strong>编码一致性</strong>:与<code>QString</code>转换时必须指定正确的编码,否则会出现乱码。</li><li><strong>性能</strong>:批量操作(如<code>append</code>大量数据)时,先<code>reserve()</code>预分配内存,避免频繁扩容。</li></ul>
<p class="maodian"></p><h2>总结</h2>
<p><code>QByteArray</code>是Qt中处理<strong>字节数据</strong>和<strong>8位文本</strong>的核心类,其API设计兼顾了安全性与便捷性。在流媒体开发中,它能有效处理协议解析、数据封装、网络IO等关键场景,是嵌入式Linux流媒体方案的必备工具。</p>
<p>到此这篇关于Qt中QByteArray​类型的使用详解的文章就介绍到这了,更多相关Qt QByteArray​类型使用内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>QT中QByteArray与char、int、float之间的互相转化</li><li>Qt基础开发之QString与QByteArray详细用法与区别及QString QByteArray互转</li><li>Qt的QJsonObject存储QByteArray的方法实现</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Qt中QByteArray​类型的使用详解