QByteArray类是一个字节数组类。
QByteArray 可用于存储原始字节(包括'\0')和传统的 8 位 '\0' 终止字符串。使用 QByteArray 比使用 const char * 方便得多。在后台,它始终确保数据后面跟着 '\0' 终止符,并使用隐式共享(写入时复制)来减少内存使用量并避免不必要的数据复制。
除了QByteArray,Qt还提供了QString类来存储字符串数据。在大多数情况下,QString 是您想要使用的类。它存储 16 位 Unicode 字符,可以轻松地在应用程序中存储non-ASCII/non-Latin-1字符。此外,QString在Qt API中始终使用。QByteArray适合的两个主要情况是,当你需要存储原始二进制数据以及当内存节省是至关重要的时(例如,使用Qt用于嵌入式Linux)。
初始化 QByteArray 的一种方法是简单地将 const char * 传递给其构造函数。例如,以下代码创建一个大小为 5 的字节数组,其中包含数据“Hello”:
QByteArray ba("Hello");
虽然 size() 是 5,但字节数组还在末尾保留一个额外的'\0'字符,这样如果使用一个函数来请求指向底层数据的指针(例如调用 data()),则指向的数据保证以'\0'结尾。
QByteArray 会制作 const char * 数据的深层副本,因此您可以稍后对其进行修改而不会遇到副作用。(如果出于性能原因,您不想创建字符数据的深层副本,请改用 QByteArray::fromRawData()。
另一种方法是使用 resize() 设置数组的大小,并初始化每个字节的数据字节。QByteArray 使用从 0 开始的索引,就像C++数组一样。要访问特定索引位置的字节,可以使用运算符 []()。在非常量字节数组上,operator[]() 返回对可在赋值左侧使用的字节的引用。例如:
QByteArray ba;
ba.resize(5);
ba[0] = 0x3c;
ba[1] = 0xb8;
ba[2] = 0x64;
ba[3] = 0x18;
ba[4] = 0xca;
对于只读访问,另一种语法是使用 at():
for (int i = 0; i < ba.size(); ++i) {
if (ba.at(i) >= 'a' && ba.at(i) <= 'f')
cout << "Found character in range [a-f]" << endl;
}
at() 可以比 operator[]() 快,因为它从不会导致发生深层复制。
要一次提取多个字节,请使用 left()、right() 或 mid()。
QByteArray 可以嵌入 '\0' 字节。size() 函数始终返回整个数组的大小,包括嵌入的 '\0' 字节,但不包括 QByteArray 添加的终止 '\0'。例如:
QByteArray ba1("ca\0r\0t");
ba1.size(); // Returns 2.
ba1.constData(); // Returns "ca" with terminating \0.
QByteArray ba2("ca\0r\0t", 3);
ba2.size(); // Returns 3.
ba2.constData(); // Returns "ca\0" with terminating \0.
QByteArray ba3("ca\0r\0t", 4);
ba3.size(); // Returns 4.
ba3.constData(); // Returns "ca\0r" with terminating \0.
const char cart[] = {'c', 'a', '\0', 'r', '\0', 't'};
QByteArray ba4(QByteArray::fromRawData(cart, 6));
ba4.size(); // Returns 6.
ba4.constData(); // Returns "ca\0r\0t" without terminating \0.
如果要获取数据长度,直到第一个'\0'字符,并排除第一个'\0'字符,请在字节数组上调用 qstrlen()。
调用 resize() 后,新分配的字节具有未定义的值。若要将所有字节设置为特定值,请调用 fill()。
要获取指向实际字符数据的指针,请调用 data() 或 constData()。这些函数返回指向数据开头的指针。指针保证保持有效,直到在 QByteArray 上调用非常量函数。还可以保证数据以'\0'字节结尾,除非 QByteArray 是从原始数据创建的。这个'\0'字节由 QByteArray 自动提供,不计入 size() 中。
QByteArray 提供了以下用于修改字节数据的基本函数:append()、prepend()、insert()、replace() 和 remove()。例如:
QByteArray x("and");
x.prepend("rock "); // x == "rock and"
x.append(" roll"); // x == "rock and roll"
x.replace(5, 3, "&"); // x == "rock & roll"
replace() 和 remove() 函数的前两个参数是开始擦除的位置和应该擦除的字节数。
当您将数据append() 到非空数组时,该数组将被重新分配,新数据将复制到其中。您可以通过调用 reserve() 来避免此行为,这会预先分配一定量的内存。你也可以调用 capacity() 来找出 QByteArray 实际分配了多少内存。不会复制附加到空数组的数据。
常见的要求是从字节数组中删除空格字符('\n'、'\t'、' '等)。如果要删除 QByteArray 两端的空格,请使用 trimmed() 。如果要删除两端的空格,并将多个连续的空格替换为字节数组中的单个空格字符,请使用 simplified()。
如果要查找 QByteArray 中特定字符或子字符串的所有匹配项,请使用 indexOf() 或 lastIndexOf()。前者从给定的索引位置开始向后搜索,后者向前搜索。如果找到字符或子字符串,两者都返回它的索引位置;否则,它们返回 -1。例如,下面是一个典型的循环,用于查找特定子字符串的所有匹配项:
QByteArray ba("We must be <b>bold</b>, very <b>bold</b>");
int j = 0;
while ((j = ba.indexOf("<b>", j)) != -1) {
cout << "Found <b> tag at index position " << j << endl;
++j;
}
如果您只想检查 QByteArray 是否包含特定字符或子字符串,请使用 contains()。如果要了解特定字符或子字符串在字节数组中出现的次数,请使用 count()。如果要将特定值的所有匹配项替换为另一个值,请使用双参数 replace() 重载之一。
可以使用重载运算符比较 QByteArrays,例如运算符<(),运算符<=(),运算符==(),运算符>=()等。比较完全基于字符的数值,并且非常快,但不是人类所期望的。QString::localeAwareCompare() 是排序用户界面字符串的更好选择。
由于历史原因,QByteArray 区分空字节数组和空字节数组。空字节数组是使用 QByteArray 的默认构造函数或通过向构造函数传递 (const char *)0 来初始化的字节数组。空字节数组是大小为 0 的任何字节数组。空字节数组始终为空,但空字节数组不一定为空:
QByteArray().isNull(); // returns true
QByteArray().isEmpty(); // returns true
QByteArray("").isNull(); // returns false
QByteArray("").isEmpty(); // returns true
QByteArray("abc").isNull(); // returns false
QByteArray("abc").isEmpty(); // returns false
除 isNull() 之外的所有函数都将空字节数组视为空字节数组。例如,data() 返回一个指针,指向空字节数组(不是空指针)的'\0'字符,并且 QByteArray() 比较等于 QByteArray("")。我们建议您始终使用 isEmpty() 并避免使用 isNull()。
注:参考Qt帮助文档
后续公众号会发布系列教程,更多内容请关注公众号:程序猿学习日记