• 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*要方便的多,而就其内部实现来讲,它会保证所有的数据以''结尾,使用隐式数据共享(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  )
    
  • 相关阅读:
    git 教程
    gruntjs
    arm linux
    2021最佳迎接元旦的方式是什么!程序员:中国新冠疫苗上市!
    元旦表白神器!C语言实现浪漫烟花表白(有背景音乐+示例源码)
    大学期间,为啥我能学好C语言?只因我做到了这五点!
    为什么都说代码改变世界?是因为这五位程序员创造了未来!
    C++丨常见的四种求最大公约数方法!赶紧收藏!
    【腾讯C++面试题】如何才能获得腾讯的offer?掌握这20道终身受益!
    惊呆了!字节跳动成唯一上榜的中国公司!它是如何做到脱颖而出的?
  • 原文地址:https://www.cnblogs.com/schips/p/framework-cpp-qt-09-QByteArray.html
Copyright © 2020-2023  润新知