- Qt 5.12實(shí)戰(zhàn)
- 朱晨冰 李建英
- 4534字
- 2021-03-26 21:56:37
3.2 字節(jié)數(shù)組類QByteArray
字節(jié)數(shù)組類QByteArray提供一個(gè)字節(jié)數(shù)組,用于存儲(chǔ)原始字節(jié)。使用QByteArray類比使用char *更方便。該類在串口通信中經(jīng)常被使用,因?yàn)榇谕ㄐ艛?shù)據(jù)都是一個(gè)一個(gè)的8位字節(jié)流。
3.2.1 初始化
通常有兩種方法可以初始化QByteArray類的對(duì)象。
第一種方法是通過(guò)const char *將其傳遞給構(gòu)造函數(shù)。例如,以下代碼創(chuàng)建一個(gè)大小為5個(gè)字節(jié)的字節(jié)數(shù)組,數(shù)據(jù)為“Hello”:
QByteArray ba("Hello");
雖然我們定義了5個(gè)字節(jié)長(zhǎng)度的字節(jié)數(shù)組對(duì)象,索引范圍從0到4,但是系統(tǒng)自動(dòng)會(huì)在字節(jié)數(shù)組對(duì)象結(jié)尾添加一個(gè)'\0'字符,這是為了某些場(chǎng)合使用方便。所以,我們?cè)谒饕?的位置可以得到字符數(shù)據(jù)'\0',比如:

第二種方法是使用resize()設(shè)置數(shù)組的大小,并初始化每個(gè)數(shù)組元素。
QByteArray ba; ba.resize(6); ba[0] = 0x3c; ba[1] = 0xb8; ba[2] = 0x64; ba[3] = 0x18; ba[4] = 0xca;
QByteArray類使用從0開(kāi)始的索引值,就像C++數(shù)組一樣。在調(diào)用resize()后,新分配的字節(jié)具有未定義的值。要將所有字節(jié)設(shè)置為特定值,可以調(diào)用fill()函數(shù),該函數(shù)的原型聲明如下:
QByteArray &QByteArray::fill(char ch, int size = -1)
其中,參數(shù)ch是要給字節(jié)數(shù)組設(shè)置的字符;size如果不是-1,就表示重新要為字節(jié)數(shù)組開(kāi)辟的空間大小。比如:

第一次調(diào)用fill()函數(shù)后,ba所有空間的內(nèi)容都是字符o了;第二次調(diào)用fill()函數(shù)后,因?yàn)閒ill()函數(shù)的第二個(gè)參數(shù)size是2,所以會(huì)重新調(diào)整ba的空間大小,變?yōu)?個(gè)字節(jié),而且內(nèi)容重新設(shè)置為"XX"。
3.2.2 訪問(wèn)某個(gè)元素
訪問(wèn)QByteArray類對(duì)象中的某個(gè)元素主要有4種方式,分別為[]、at()、data[]和constData[]。其中,[]和data[]方式為可讀可寫(xiě),at()和constData[]方式僅為可讀。如果只是進(jìn)行讀操作,則通過(guò)at()和constData[]方式的訪問(wèn)速度最快,因?yàn)楸苊饬藦?fù)制處理。
at()可以比operator []()更快,就是因?yàn)榍罢卟粫?huì)發(fā)生深層復(fù)制。
【例3.2】 訪問(wèn)QByteArray類對(duì)象中的單個(gè)數(shù)據(jù)
(1)啟動(dòng)Qt Creator 4.8.2,新建一個(gè)控制臺(tái)項(xiàng)目,項(xiàng)目名為test。
(2)在main.cpp中輸入如下代碼:

qDebug()會(huì)輸出ba[2]對(duì)應(yīng)的字符,ASCII碼為0x64的字符是'd'。
(3)按Ctrl+R快捷鍵運(yùn)行項(xiàng)目,結(jié)果如圖3-2所示。

圖3-2
3.2.3 截取子字符串
要一次提取多個(gè)字節(jié),可使用函數(shù)left()、right()或mid()。
(1)函數(shù)left()返回從索引0位置開(kāi)始、長(zhǎng)度為len的子字節(jié)數(shù)組,該函數(shù)的原型聲明如下:
QByteArray left(int len)
其中,參數(shù)len表示從數(shù)組左邊開(kāi)始要截取的字節(jié)數(shù)組的長(zhǎng)度,如果len大于原來(lái)整個(gè)字節(jié)數(shù)組的長(zhǎng)度,則返回整個(gè)字節(jié)數(shù)組。下列代碼演示了函數(shù)left()函數(shù)的使用:
QByteArray x("Pineapple"); QByteArray y = x.left(4); // y == "Pine"
(2)函數(shù)right()用來(lái)獲取從字節(jié)數(shù)組最后一個(gè)字節(jié)數(shù)據(jù)開(kāi)始,向前面截取len個(gè)字節(jié)并返回截取的子字節(jié)數(shù)組。該函數(shù)的原型聲明如下:
QByteArray right(int len)
其中,參數(shù)len表示從右邊開(kāi)始要截取的子字節(jié)數(shù)組的長(zhǎng)度,如果len大于原來(lái)整個(gè)字節(jié)數(shù)組的長(zhǎng)度,則返回整個(gè)字節(jié)數(shù)組。下列代碼演示了函數(shù)right()函數(shù)的使用:
QByteArray x("Pineapple"); QByteArray y = x.right(5); // y == "apple"
(3)函數(shù)mid()返回從指定索引位置開(kāi)始,向右邊(即后面)長(zhǎng)度為len的子字節(jié)數(shù)組。該函數(shù)的原型聲明如下:
QByteArray mid(int pos, int len = -1)
其中,參數(shù)pos表示開(kāi)始截取的索引,索引值從0開(kāi)始;len表示要截取的子字節(jié)數(shù)組的長(zhǎng)度,如果len為-1(默認(rèn)值)或pos+len大于原字節(jié)數(shù)組的長(zhǎng)度,則返回從pos開(kāi)始一直到右邊剩下的全部字節(jié)數(shù)組。下列代碼演示了函數(shù)mid()函數(shù)的使用:

3.2.4 獲取字節(jié)數(shù)組的大小
可以用成員函數(shù)size、length和count來(lái)獲取字節(jié)數(shù)組的大小。除了名字不同,這3個(gè)函數(shù)是等同的,函數(shù)的原型聲明如下:
int size(); int length(); int count();
這3個(gè)函數(shù)返回字節(jié)數(shù)組中的字節(jié)數(shù)。Size()函數(shù)的用法如下:
QByteArray ba("Hello"); int n = ba.size(); // n == 5
執(zhí)行后,n等于5。可見(jiàn),size()并不包含字符串末尾自動(dòng)添加的'\0'。另外,如果以字符串形式初始化,中間有'\0',則size()不會(huì)統(tǒng)計(jì)'\0'及其后面的字符。
QByteArray ba2("He\0llo"); int n = ba2.size(); // n == 2
執(zhí)行后,n等于2。通過(guò)resize分配空間,然后通過(guò)逐個(gè)賦值來(lái)進(jìn)行初始化的話,中間某個(gè)字節(jié)數(shù)據(jù)是'\0',并不會(huì)被size()函數(shù)截?cái)唷1热纾?/p>

3.2.5 數(shù)據(jù)轉(zhuǎn)換與處理
從串口讀取到的QByteArray數(shù)據(jù)一般需要進(jìn)行提取和解析,此時(shí)就需要將QByteArray數(shù)據(jù)轉(zhuǎn)換為各種類型的數(shù)據(jù)。常用的轉(zhuǎn)換包括:
(1)轉(zhuǎn)為Hex,用于顯示十六進(jìn)制,這點(diǎn)在調(diào)試時(shí)特別有用,因?yàn)榇蠖郒EX碼是沒(méi)有字符顯示的,如0x00、0x20等。
(2)轉(zhuǎn)為不同進(jìn)制數(shù)值并顯示,如二進(jìn)制、八進(jìn)制、十進(jìn)制和十六進(jìn)制等數(shù)值。
(3)轉(zhuǎn)為整數(shù)類型、浮點(diǎn)類型等的數(shù)據(jù)類型。
(4)字母大小寫(xiě)進(jìn)行轉(zhuǎn)換。
(5)轉(zhuǎn)為字符串類型。
1. Hex轉(zhuǎn)換(十六進(jìn)制轉(zhuǎn)換)
QByteArray類的公有靜態(tài)函數(shù)QByteArray::fromHex可以把十六進(jìn)制編碼的數(shù)據(jù)轉(zhuǎn)換為字符(char)類型的數(shù)據(jù),并存儲(chǔ)到QByteArray類對(duì)象中。該函數(shù)的原型聲明如下:
QByteArray fromHex(const QByteArray &hexEncoded)
其中,參數(shù)hexEncoded是十六進(jìn)制編碼的字節(jié)數(shù)組。由于該函數(shù)并不檢查參數(shù)的有效性,因此遇到非十六進(jìn)制數(shù)據(jù)則直接略過(guò),然后繼續(xù)處理剩余的數(shù)據(jù)。下列代碼演示了fromHex()函數(shù)的使用:

字符'5'和'1'為一組,轉(zhuǎn)為十六進(jìn)制數(shù)據(jù)0x51,0x51對(duì)應(yīng)的十進(jìn)制數(shù)據(jù)是81,ASCII碼為81的字符是'Q'。
與fromHex()相逆的函數(shù)是toHex(),該函數(shù)將字節(jié)數(shù)組中十六進(jìn)制的數(shù)值編碼轉(zhuǎn)化為字符,它的原型聲明如下:
QByteArray toHex()
下列代碼演示了toHex()函數(shù)的使用:

索引為0的字節(jié)數(shù)據(jù)為0x30,直接轉(zhuǎn)為兩個(gè)字符'3'和'0'。
2. 數(shù)值轉(zhuǎn)換與輸出
盡管QByteArray類是一個(gè)集合,但也可以作為一個(gè)特殊形式的數(shù)值來(lái)用,其靈活的轉(zhuǎn)換格式可大大方便各種格式數(shù)據(jù)轉(zhuǎn)換與顯示的需求,如顯示二進(jìn)制和十六進(jìn)制、顯示科學(xué)記數(shù)和指定小數(shù)位的數(shù)值。QByteArray類的公有靜態(tài)函數(shù)number可以完成這些功能。該函數(shù)可以將某個(gè)整數(shù)轉(zhuǎn)為某種進(jìn)制的字符數(shù)組,函數(shù)number的原型聲明如下:
QByteArray number(int n, int base = 10)
其中,參數(shù)n是要轉(zhuǎn)變的整數(shù);base是要進(jìn)行轉(zhuǎn)換的進(jìn)制,進(jìn)制取值范圍為2到36,即從二進(jìn)制到三十六進(jìn)制。該函數(shù)返回整數(shù)n對(duì)應(yīng)的base進(jìn)制的字符數(shù)組。下列代碼演示了number()函數(shù)的使用:

與此公有靜態(tài)函數(shù)功能類似的公有函數(shù)是setNum(),該函數(shù)也是將某個(gè)整數(shù)轉(zhuǎn)為某種進(jìn)制的字符數(shù)組,函數(shù)的原型聲明如下:
QByteArray & setNum(int n, int base = 10)
其中,參數(shù)n是要轉(zhuǎn)變的整數(shù);base是要進(jìn)行轉(zhuǎn)換的進(jìn)制,進(jìn)制取值范圍為2到36,即從二進(jìn)制到三十六進(jìn)制。該函數(shù)返回整數(shù)n對(duì)應(yīng)的base進(jìn)制的字符數(shù)組。下列代碼演示了setNum()函數(shù)的使用:
QByteArray ba; int n = 63; ba.setNum(n); // ba == "63" ba.setNum(n, 16); // ba == "3f"
因?yàn)椴皇庆o態(tài)函數(shù),所以要用對(duì)象來(lái)調(diào)用。此外,根據(jù)setNum()函數(shù)第一個(gè)參數(shù)的類型,setNum()函數(shù)可以有多種版本,比如:
QByteArray &QByteArray::setNum(ushort n, int base = 10) QByteArray &QByteArray::setNum(short n, int base = 10) QByteArray &QByteArray::setNum(uint n, int base = 10) QByteArray &QByteArray::setNum(qlonglong n, int base = 10)
用法類似,只是n的取值范圍不同。
除了整數(shù)之外,還能把數(shù)值按指定格式和小數(shù)位轉(zhuǎn)換輸出,所調(diào)用的函數(shù)依舊是number(),只不過(guò)參數(shù)形式變了:
QByteArray number(double n, char f = 'g', int prec = 6)
其中,參數(shù)n是要進(jìn)行轉(zhuǎn)換的實(shí)數(shù);f表示轉(zhuǎn)換格式,取值如下:
· e:采用指數(shù)法表示實(shí)數(shù),此時(shí)實(shí)數(shù)的格式如[-]9.9e[+|-]999。
· E:格式同e,不過(guò)E要大寫(xiě)。
· f:普通小數(shù)表示法,此時(shí)格式如[-]9.9。
· g:使用e或f格式,第三個(gè)參數(shù)表示有效數(shù)字位的個(gè)數(shù)。
· G:使用E或f格式,第三個(gè)參數(shù)表示有效數(shù)字位的個(gè)數(shù)。
當(dāng)參數(shù)f為'e'、'E'或'f '時(shí),prec表示十進(jìn)制小數(shù)點(diǎn)后小數(shù)部分的位數(shù);當(dāng)f為'g'或'G'時(shí),prec表示有效數(shù)字位數(shù)的最大數(shù)目。注意,小數(shù)位要四舍五入。
【例3.3】 實(shí)數(shù)轉(zhuǎn)為字節(jié)數(shù)組
(1)啟動(dòng)Qt Creator 4.8.2,新建一個(gè)控制臺(tái)項(xiàng)目,項(xiàng)目名為test。
(2)在main.cpp中輸入如下代碼:

我們分別使用了5種格式將實(shí)數(shù)12345.6轉(zhuǎn)換為字節(jié)數(shù)組,最后輸出結(jié)果。
(3)按Ctrl+R快捷鍵運(yùn)行項(xiàng)目,結(jié)果如圖3-3所示。

圖3-3
3.2.6 字母大小寫(xiě)的轉(zhuǎn)換
QByteArray類對(duì)象若為帶大小寫(xiě)字母的字符串,可調(diào)用函數(shù)toUpper()和toLower()實(shí)現(xiàn)字母大小寫(xiě)的轉(zhuǎn)換。函數(shù)toUpper()的原型聲明如下:
QByteArray toUpper()
函數(shù)很簡(jiǎn)單,沒(méi)有參數(shù),直接返回轉(zhuǎn)換成大寫(xiě)字母后的字節(jié)數(shù)組。在轉(zhuǎn)換過(guò)程中,碰到已經(jīng)是大寫(xiě)的字母就忽略。用法舉例如下:
QByteArray x("Qt by THE QT COMPANY"); QByteArray y = x.toUpper(); // y == "QT BY THE QT COMPANY"
函數(shù)toLower()也很簡(jiǎn)單,它的原型聲明如下:
QByteArray toLower()
返回轉(zhuǎn)換成小寫(xiě)字母后的字節(jié)數(shù)組。在轉(zhuǎn)換過(guò)程中,碰到已經(jīng)是小寫(xiě)的字母就忽略。用法舉例如下:
QByteArray x("Qt by THE QT COMPANY"); QByteArray y = x.toLower(); // y == "qt by the qt company"
除了字母大小寫(xiě)的轉(zhuǎn)換,QByteArray類還提供了判斷是大寫(xiě)字母還是小寫(xiě)字母的成員函數(shù)isUpper和isLower。其中,isLower()函數(shù)的原型聲明如下:
bool isLower()
如果字節(jié)數(shù)組中只包含小寫(xiě)字母則返回true,否則返回false。
3.2.7 字符串?dāng)?shù)值轉(zhuǎn)為各類數(shù)值
QByteArray類對(duì)象的字符若都為數(shù)值,則可通過(guò)to**函數(shù)(也稱為方法)轉(zhuǎn)為各種類型的數(shù)據(jù),示例如下:

3.2.8 QByteArray與char*互轉(zhuǎn)
成員函數(shù)data可以返回指向字節(jié)數(shù)組中存儲(chǔ)數(shù)據(jù)的指針。該函數(shù)的原型聲明如下:
char *data();
該指針可用于訪問(wèn)和修改組成數(shù)組的元素。可以指定具體訪問(wèn)字節(jié)數(shù)組中的某一個(gè),比如ba.data()[0]表示訪問(wèn)第0個(gè)。
如果要把char*轉(zhuǎn)為QString,可以直接作為參數(shù)傳入QByteArray類的構(gòu)造函數(shù)中:
char* pt; QByteArray byte(str);
我們來(lái)看一個(gè)小例子。
【例3.4】 返回char*并打印內(nèi)容。
(1)啟動(dòng)Qt Creator 4.8.2,新建一個(gè)控制臺(tái)項(xiàng)目,項(xiàng)目名為test。
(2)在test.cpp中輸入如下代碼:

(3)按Ctrl+R快捷鍵運(yùn)行項(xiàng)目,結(jié)果如圖3-4所示。

圖3-4
3.2.9 QByteArray與std::string互轉(zhuǎn)
string是C++標(biāo)準(zhǔn)庫(kù)中的字符串類型。QByteArray類提供的成員函數(shù)toStdString()可以將字節(jié)數(shù)組轉(zhuǎn)為string。該函數(shù)的原型聲明如下:
std::string toStdString();
與該函數(shù)相反的函數(shù)是靜態(tài)成員函數(shù)fromStdString(),它將string數(shù)據(jù)轉(zhuǎn)為字節(jié)數(shù)組,該函數(shù)的原型聲明如下:
[static] QByteArray QByteArray::fromStdString(const std::string &str);
其中,參數(shù)str是要轉(zhuǎn)換的string字符串。函數(shù)返回轉(zhuǎn)換后的字節(jié)數(shù)組。注意,轉(zhuǎn)換的是str的一份備份,轉(zhuǎn)換過(guò)程并不會(huì)影響str本身的內(nèi)容。
3.2.10 與字符串QString互轉(zhuǎn)
QString是Qt的字符串類,QByteArray是byte的數(shù)組。它們之間也可以互轉(zhuǎn)。
QByteArray與QString互轉(zhuǎn)極為簡(jiǎn)單,二者在本質(zhì)上是類似的,都是連續(xù)存儲(chǔ)的,區(qū)別是前者可以存儲(chǔ)無(wú)法顯示的字符,后者只存儲(chǔ)可顯示的字符。如QByteArray類對(duì)象可以存儲(chǔ)0x00-0x19,而QString類對(duì)象只能存儲(chǔ)如0x30等可顯示字符(0x20-0x7E)。有關(guān)可顯示字符,可參見(jiàn)ASCII表,相信大家在學(xué)習(xí)C語(yǔ)言時(shí)都了解過(guò)了。
String轉(zhuǎn)QByteArray的代碼如下:
QString str=QString("hello world!"); QByteArray arr = str.toLatin1();
QByteArray轉(zhuǎn)QString的代碼如下:
QByteArray arr("hello world!"); QString str = arr;
下面再看一下QByteArray轉(zhuǎn)為QString示例:
QByteArray ba("abc123"); QString str = ba; //或str.prepend(ba); qDebug()<<str ; //輸出:"abc123"
QString轉(zhuǎn)為QByteArray示例:
QString str("abc123"); QByteArray ba = str.toLatin1(); qDebug()<<ba; //輸出:"abc123"
3.2.11 QByteArray與自定義結(jié)構(gòu)體之間的轉(zhuǎn)化
在Socket網(wǎng)絡(luò)編程中,網(wǎng)絡(luò)數(shù)據(jù)一般是uchar類型(最好是用uchar來(lái)傳輸,避免莫名其妙的錯(cuò)誤,另外用char類型也可以),在Qt中則可以使用QByteArray類。QByteArray類在QSocket共享庫(kù)中,根據(jù)C++中char*數(shù)據(jù)與結(jié)構(gòu)體之間的映射可以實(shí)現(xiàn)結(jié)構(gòu)體與QByteArray的轉(zhuǎn)化。下面來(lái)看一段代碼:


上面這段程序的運(yùn)行結(jié)果如下:

3.2.12 判斷是否為空
可以使用函數(shù)isEmpty()來(lái)判斷字節(jié)數(shù)組是否為空,即size是否為0。函數(shù)isEmpty()的原型聲明如下:
bool isEmpty();
如果字節(jié)數(shù)組的size為0,則返回true,否則返回false。
下列代碼演示isEmpty()函數(shù)的使用:
QByteArray().isEmpty(); // returns true QByteArray("").isEmpty(); // returns true QByteArray("abc").isEmpty(); // returns false
3.2.13 向前搜索和向后搜索
函數(shù)indexOf()返回該字節(jié)數(shù)組中第一次出現(xiàn)字節(jié)數(shù)組ba的索引位置,從索引位置向前搜索。該函數(shù)的原型聲明如下:
int indexOf(const QByteArray &ba, int from = 0);
其中,參數(shù)ba為要查找的目標(biāo)字節(jié)數(shù)組ba,找到ba就返回索引值;from表示開(kāi)始搜索位置對(duì)應(yīng)的索引值,默認(rèn)從索引值為0的位置開(kāi)始搜索。如果找到ba,則返回第一次出現(xiàn)ba所在位置對(duì)應(yīng)的索引值,如果沒(méi)有找到,則返回-1。注意,所謂向前搜索,就是朝著索引值增大的方向搜索,即在數(shù)組中從左到右搜索。
下列代碼演示了這個(gè)函數(shù)的使用方法:

indexOf()還可以搜索char*和QString類型的數(shù)據(jù),函數(shù)的原型聲明如下:
int indexOf(const char *str, int from = 0); int indexOf(const QString &str, int from = 0);
此外,還有以某個(gè)字符為搜索對(duì)象的函數(shù)聲明形式:
int indexOf(char ch, int from = 0);
使用示例如下:

indexOf()函數(shù)是向前搜索,另外還有一個(gè)函數(shù)lastIndexOf()是向后搜索,該函數(shù)的原型聲明如下:
int lastIndexOf(const QByteArray &ba, int from = -1);
3.2.14 插入
函數(shù)insert()可以在某個(gè)索引位置上插入字節(jié)數(shù)組,該函數(shù)的原型聲明如下:
QByteArray & insert(int i, const QByteArray &ba);
其中,i為要插入的索引位置;ba為要插進(jìn)去的字節(jié)數(shù)組對(duì)象。使用示例如下:
QByteArray ba("Meal"); ba.insert(1, QByteArray("ontr")); // ba == "Montreal"
此外,也可以在某個(gè)位置插入一個(gè)或多個(gè)字符,有兩個(gè)函數(shù),這兩個(gè)函數(shù)的原型聲明如下:
QByteArray & QByteArray::insert(int i, char ch); QByteArray & insert(int i, int count, char ch);
其中,i為要插入的索引位置;count是要插入的字符個(gè)數(shù),其實(shí)就是count個(gè)ch;ch為要插入的字符。
另外,還有一種重載形式,就是插入char*類型的數(shù)據(jù),有兩種函數(shù)的原型聲明形式:
QByteArray & insert(int i, const char *str); QByteArray & QByteArray::insert(int i, const char *str, int len);
第一種形式不帶長(zhǎng)度,插入全部str;第二種形式帶長(zhǎng)度len,len表示str中的len個(gè)字節(jié)。
此外,Qt還提供了prepend()函數(shù),該函數(shù)在原字符串開(kāi)頭插入另一個(gè)字符串。
- 碼上行動(dòng):零基礎(chǔ)學(xué)會(huì)Python編程(ChatGPT版)
- SQL語(yǔ)言從入門(mén)到精通
- Web全棧工程師的自我修養(yǎng)
- HTML5入門(mén)經(jīng)典
- 碼上行動(dòng):用ChatGPT學(xué)會(huì)Python編程
- 硅谷Python工程師面試指南:數(shù)據(jù)結(jié)構(gòu)、算法與系統(tǒng)設(shè)計(jì)
- 從零開(kāi)始學(xué)Linux編程
- MySQL從入門(mén)到精通(軟件開(kāi)發(fā)視頻大講堂)
- Mobile Device Exploitation Cookbook
- Internet of Things with ESP8266
- UI設(shè)計(jì)全書(shū)(全彩)
- Spring技術(shù)內(nèi)幕:深入解析Spring架構(gòu)與設(shè)計(jì)原理(第2版)
- AI自動(dòng)化測(cè)試:技術(shù)原理、平臺(tái)搭建與工程實(shí)踐
- SSH框架企業(yè)級(jí)應(yīng)用實(shí)戰(zhàn)
- Greenplum構(gòu)建實(shí)時(shí)數(shù)據(jù)倉(cāng)庫(kù)實(shí)踐