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  )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM