QT学习:09 QByteArray

---
title: framework-cpp-qt-09-QByteArray
EntryName: framework-cpp-qt-09-QByteArray
date: 2020-04-16 16:32:30
categories:
tags:
- qt
- c/c++
---

章节描述:
QByteArray类提供存放二进制数据,什么数据都能保存。

介绍

QByteArray的本质上是一个字节数组。类似于unsigned char[]

由于QByteArray封装的功能很多,使用起来比char*要方便的多,而就其内部实现来讲,它会保证所有的数据以'\0'结尾,使用隐式数据共享(copy-on-write)来减少内存消耗以及不必要的数据拷贝。

而QString是一个字符串,其内部其实也是unsigned char[],但是这个数组是用于保存unicode字符的数组。对QString进行操作的时候,是按照字符串的角度来进行调用的。QString自动完成了一些字符串到字节数组的转换工作。

初始化

QByteArray()

QByteArray(const char *data, int size = -1)

QByteArray(int size, char ch)

QByteArray(const QByteArray &other)

QByteArray(QByteArray &&other)

访问与赋值

访问QByteArray主要有4种方式,分别为[]at()data[]constData[]

其中[]data[]为可读可写,at()constData[]仅为可读。

如果仅是读,则通过at()constData[]访问速度最快,因可避免复制处理。示例如下:

int main(int argc, char *argv[])
{
    char buffer[7] = "Schips";
    QByteArray ba(buffer);

    qDebug()<< ba;

    ba[0] = '0';
    //ba.at(1) = '1'; // error
    ba.data()[2] = '2';

    qDebug()<<"[0]"<<ba[0]; //[] S -> 0
    qDebug()<<"[1]"<<ba[1]; //[] c
    qDebug()<<"at(2)"<<ba.at(2); //at() h -> 2
    qDebug()<<"data(3)"<<ba.data()[3]; //data() i
    qDebug()<<"constData(4)"<<ba.constData()[4]; //constData() p
    qDebug()<<"constData(5)"<<ba.constData()[5]; //constData() s

    return 0;
}

修改

QByteArray提供了很多修改字节的方法: append()/ prepend(),/insert(), replace(), remove()。如下所示

QByteArray & append(const QByteArray &ba)
QByteArray & append(int count, char ch)
QByteArray & append(const char *str)
QByteArray & append(const char *str, int len)
QByteArray & append(char ch)
QByteArray & append(const QString &str)


QByteArray & insert(int i, const QByteArray &ba)
QByteArray & insert(int i, int count, char ch)
QByteArray & insert(int i, const char *str)
QByteArray & insert(int i, const char *str, int len)
QByteArray & insert(int i, char ch)
QByteArray & insert(int i, const QString &str)


QByteArray & replace(int pos, int len, const QByteArray &after)
QByteArray & replace(int pos, int len, const char *after, int alen)
QByteArray & replace(int pos, int len, const char *after)
QByteArray & replace(char before, const char *after)
QByteArray & replace(char before, const QByteArray &after)
QByteArray & replace(const char *before, const char *after)
QByteArray & replace(const char *before, int bsize, const char *after, int asize) 
QByteArray & replace(const QByteArray &before, const QByteArray &after)
QByteArray & replace(const QByteArray &before, const char *after)
QByteArray & replace(const char *before, const QByteArray &after)
QByteArray & replace(char before, char after)
QByteArray & replace(const QString &before, const char *after)
QByteArray & replace(char before, const QString &after)
QByteArray & replace(const QString &before, const QByteArray &after)


QByteArray & remove(int pos, int len)

例子:

QByteArray x("and");

x.prepend("rock ");         // x == "rock and"
x.append(" roll");          // x == "rock and roll"
x.replace(5, 3, "&");       // x == "rock & roll"
x.remove(0, 3);             // x == "k & roll"

查找

使用indexof函数从前向后获取索引第一次出现的位置

int indexOf(const QByteArray &ba, int from = 0) const
int indexOf(const char *str, int from = 0) const
int indexOf(char ch, int from = 0) const
int indexOf(const QString &str, int from = 0) const

使用lastIndexof函数从后向前获取索引第一次出现的位置

int lastIndexOf(const QByteArray &ba, int from = -1) const
int lastIndexOf(const char *str, int from = -1) const
int lastIndexOf(char ch, int from = -1) const
int lastIndexOf(const QString &str, int from = -1) const

例子:

QByteArray x("crazy azimuths");
QByteArray y("az");
qDebug() <<  x.indexOf(y);              // returns 2
qDebug() <<  x.indexOf(y, 1);           // returns 2
qDebug() <<  x.indexOf(y, 10);          // returns -1

qDebug() << x.indexOf(y);             // returns 6
qDebug() << x.lastIndexOf(y);           // returns 6
qDebug() << x.lastIndexOf(y, 6);        // returns 6
qDebug() << x.lastIndexOf(y, 5);        // returns 2
qDebug() << x.lastIndexOf(y, 1);        // returns -1

使用contains 判断数据是否存在

bool contains(const QByteArray &ba) const
bool contains(const char *str) const
bool contains(char ch) const

数据转换与处理

常用转换包括:转为HEX、转为不同进制数值并显示、转为整型、浮点型等数值类型、大小写转换、转为字符串类型。

Hex转换

用于显示十六进制,这点在调试时特别有用,因为大多HEX码是没有字符显示的,如0x00、0x20等等;

QByteArray text = QByteArray::fromHex("517420697320677265617421");
qDebug() << text.data();            // returns "Qt is great!"

QByteArray raw ("Qt is great!");
QString hexText;
hexText = raw.toHex();
qDebug() << hexText;

转为不同进制

转为不同进制数值并显示,如二进制、八进制、十进制和十六进制等;

QByteArray &QByteArray::setNum(int n, int base = 10)
// base : 进制
QByteArray QByteArray::number(int n, int base = 10)

尽管QByteArray是一个集合,但也可以作为一个特殊形式的数值用,其灵活的转换格式,可大大方便各种格式数据转换与显示的需求。如显示二进制和十六进制、显示科学计数和指定小数位的数值。示例如下:

把单个字符转为2-36进制数据格式:

int n = 63;
qDebug()<<QByteArray::number(n);              // returns "63"
qDebug()<<QByteArray::number(n, 16);          // returns "3f"
qDebug()<<QByteArray::number(n, 16).toUpper();  // returns "3F"
qDebug()<<QByteArray::number(n, 2);          // returns "111111"
qDebug()<<QByteArray::number(n, 8);          // returns "77"

按照指定进制格式直接复制,其中n可以是各类常见数值类型:

QByteArray ba;
int n = 63;
ba.setNum(n);           // ba == "63"
ba.setNum(n, 16);       // ba == "3f"

类型转换

转为整型、浮点型等数值类型;

QByteArray toBase64() const
QByteArray toBase64(QByteArray::Base64Options options) const
CFDataRef  toCFData() const
double toDouble(bool *ok = nullptr) const
float toFloat(bool *ok = nullptr) const
QByteArray toHex() const
QByteArray toHex(char separator) const
int toInt(bool *ok = nullptr, int base = 10) const
long 
toLong(bool *ok = nullptr, int base = 10) const
qlonglong  toLongLong(bool *ok = nullptr, int base = 10) const
QByteArray toLower() const
NSData * toNSData() const

QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(), const QByteArray &include = QByteArray(), char percent = '%') const

CFDataRef toRawCFData() const
NSData *toRawNSData() const

short toShort(bool *ok = nullptr, int base = 10) const
std::string  toStdString() const
uint toUInt(bool *ok = nullptr, int base = 10) const
ulong toULong(bool *ok = nullptr, int base = 10) const
qulonglong toULongLong(bool *ok = nullptr, int base = 10) const
ushort  toUShort(bool *ok = nullptr, int base = 10) const

例子:

QByteArray strInt("1234");
bool ok0;
qDebug() << strInt.toInt();   // return 1234
qDebug() << strInt.toInt(&ok0,16);   // return 4660, 默认把strInt作为16进制的1234,对应十进制数值为4660

QByteArray string("1234.56");
bool ok1;
qDebug() << string.toInt();   // return 0, 小数均视为0
qDebug() << string.toInt(&ok1,16);   // return 0, 小数均视为0
qDebug() << string.toFloat();   // return 1234.56
qDebug() << string.toDouble();   // return 1234.56

QByteArray str("FF");
bool ok2;
qDebug() << str.toInt(&ok2, 16);     // return 255, ok2 == true
qDebug() << str.toInt(&ok2, 10);     // return 0, ok2 == false, 转为十进制失败

大小写转换

QByteArray若为带大小写的字符串,可通过toUpper()和toLower()方法实现大小写转换,示例如下:

QByteArray x("Qt by THE QT COMPANY");
QByteArray y = x.toLower();
// y == "qt by the qt company"

QByteArray z = x.toUpper();
// z == "QT BY THE QT COMPANY"

转为字符串类型

QByteArrayQString互转极为简单,二者从本质上类似,都是连续存储,区别是前者可以存无法显示的字符,后者只存可显示的字符。如QByteArray可以存0x00-0x19,而QString则存储0x20-0x7E(可参见ASCII表)的字符。

QByteArray ba1("abc123");
QString str1 = ba1; 
//或str1.prepend(ba1);
qDebug()<<str1 ;
//输出:"abc123"

QString str2("abc123");
QByteArray ba2 = str2.toLatin1();
qDebug()<<ba2;
//输出:"abc123"

申请内存

QByteArray可以自动调整内存大小,如果希望提高性能,则可以使用reseve()函数来主动分动一段内存空间, 如:

QByteArray byteArray;
byteArray.reserve(30); /*!<申请30个字节的空间*/

该内存空间不会主动释放,须使用以下方式进行释放

byteArray.squeeze();   /*!<释放内存*/

与结构体之间的转换

一般用于可用于网络传输、读写等。

结构体转QByteArray

#include <QByteArray>
#include <QDebug>

// 定义某个结构体
typedef struct _Header{
    int channel;
    int type;
} Header;

...

// 在某处的函数调用中
{
    // 声明并赋值结构体
    Header header ={0};
    header.channel = 1001;
    header.type = 1;

    // 声明QByteArray
    QByteArray array;
    // 使用 有关的赋值函数,例如 append 或者 insert 来进行操作
    array.append((char*)&Header, sizeof(Header));
}

QByteArray转结构体

// 紧接着上面的例子。
    // 通过 QByteArray::data 方法获取 地址内容 的首地址
    Header *getHeader = (Header*)array.data();

    // 此后,正常操作数据即可。例如,将其赋值到 某个 结构体中
    Header header_out ={0};
    memcpy(&header_out, getHeader, sizeof(header_out));

    // 验证一下
    qDebug() << header_out.channel;
    qDebug() << header_out.type;

例程

#include <QByteArray>
#include <QDebug>
#include <stdlib.h>

typedef struct Header{
    int channel;
    int type;
} Header;

typedef struct Msg{
    Header header;
    char content[128];

    friend QDebug operator << (QDebug os, Msg msg){

        os << "("
           << " channel:" << msg.header.channel
           << " type:" << msg.header.type
           << " content:" << msg.content
           << " )";

        return os;
    }

}Msg;

typedef struct PeerMsg{

    PeerMsg(const int &ip, const int &por) : ipV4(ip), port(por) {}

    int ipV4;
    int port;

    friend QDebug operator << (QDebug os, PeerMsg msg){

        os << "( " << " ipV4:" << QString::number(msg.ipV4)
           << " port:" << QString::number(msg.port)
           << " )";

        return os;
    }

} PeerMsg;

int main(void)
{
    Msg msg;
    msg.header.channel = 1001;
    msg.header.type = 1;
    memcpy(msg.content, "ABCDEFG", sizeof("ABCDEFG"));

    qDebug() << msg;

    QByteArray array;
    array.append((char*)&msg, sizeof(msg));
    Msg *getMsg = (Msg*)array.data();
    qDebug() << *getMsg;

    QByteArray totalByte;
    PeerMsg peerMsg(123456, 10086);
    totalByte.append((char*)&peerMsg, sizeof(PeerMsg));
    totalByte.append(array, array.size());

    PeerMsg *getByte = (PeerMsg*)totalByte.data();
    qDebug() << *getByte;
    QByteArray contentmsg = totalByte.right(totalByte.size() - sizeof(*getByte));
    Msg *getMsg2 = (Msg*)contentmsg.data();
    qDebug() << *getMsg2;

    return 0;
}

输出结果:

(  channel: 1001  type: 1  content: ABCDEFG  )
(  channel: 1001  type: 1  content: ABCDEFG  )
(   ipV4: "123456"  port: "10086"  )
(  channel: 1001  type: 1  content: ABCDEFG  )

原文链接: https://www.cnblogs.com/schips/p/framework-cpp-qt-09-QByteArray.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    QT学习:09 QByteArray

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/342391

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午1:34
下一篇 2023年3月2日 上午1:34

相关推荐