mysql中图片用什么数据类型_在Qt中,如何用QDataStream正确操作QString数据类型

v2-48fc7fe725e2787e9203d769932a2c3b_1440w.jpg?source=172ae18b

总第011篇

本文主要梳理总结了在使用Qt做项目开发过程中,用QDataStream来正确操作QString类型数据的问题。这个地方非常容易出错,笔者当时在遇到这个问题时,耗费了大量的时间查找资料,现将解决方法总结成文,方便后来者借鉴之。

QDataStream类提供的读写二进制数据的能力很强,使用也非常方便,非常适合将自定义数据类型进行序列化网络传输,但在使用过程中也有一些问题需要特别注意。

1.QDataStream对QString的操作

先看下面一段代码:

char fileName[100];
memset(fileName,0,100);
QByteArray packData;
packData.clear();
QDataStream in(&packData,QIODevice::ReadWrite);

in.setByteOrder(QDataStream::BigEndian);
in.setVersion(QDataStream::Qt_5_9);

in<<fileName;
qDebug()<<"print : "<<packData.length();

以上代码的输出结果是:print: 5 。为什么结果会是5呢? 继续向下看下面的代码。

char fileName[100];
memset(fileName,1,100);
QByteArray packData;
packData.clear();
QDataStream in(&packData,QIODevice::ReadWrite);

in.setByteOrder(QDataStream::BigEndian);
in.setVersion(QDataStream::Qt_5_19);

in<<fileName;
qDebug()<<"print : "<<packData.length();

以上的代码输出结果是:print: 113。 上面两段代码展示了QDataStream在写字符数组的情况。我相信,对于这个输出结果,你或多或少都会有一些疑问。

要弄明白这些问题,我们首先要清楚sizeofsizelength 的区别:

 QString s="abcdefg";
 qDebug()<<"sizeof:"<<sizeof(s);      // 4
 qDebug()<<"length:"<<s.length();    // 7
 qDebug()<<"size:"<<s.size();       // 7

sizeof不是函数,lengthsize都是函数。sizeof返回的是对象所占内存空间的大小 ,例如32位机器上,int占4字节,double占用8字节。对于QString,其源码中只有一个非静态成员变量Data *d;,其它变量全部是static类型的,不占空间,所以sizeof(s)的大小是4。QString源码中关于sizelength的部分如下所示:

Data *d;
inline int QString::length() const { return d->size; }

inline int size() const { return d->size; }

可以发现,sizelength两者是一样的,都是返回字符串的长度。

Qt中几个数据类型与C++类型以及sizeof的对应关系如下表所示:

我们在使用QDataStream类型时,一定要注意每种类型所占用的字节大小。在操作通用内置类型时,代码可以这样写:

QByteArray ba;
QDataStream ds(&ba,QIODevice::WriteOnly);
ds<<quint8(1)<<quint16(2)<<quint32(3);  //1+2+4
qDebug()<<"size:"<<ba.size();   // 7

但是在操作QString类型数据时,会出现问题,这也是本文着重要讲解的地方。如下面代码:

QByteArray ba;
QDataStream ds(&ba,QIODevice::WriteOnly);
QString  s="e";
ds<<s;
qDebug()<<"size:"<<ba.size();   // 6

为什么结果是6呢?我们再来看源码。从qstring.cpp中找到以下源码如下:

QDataStream  &operator<< (QDataStream &out, const QString &str)
{
    if (out.version() == 1) 
   {
        out << str.toLatin1();
    } 
else {
        if (!str.isNull() || out.version() < 3) 
          {
            if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian))
           {
                out.writeBytes(reinterpret_cast<const char *>(str.unicode()), sizeof(QChar) * str.length());
            }
            ...

我们可以看到,QDataStream对不同类型的处理是不同的,这里对QString处理是先判断版本,即我们通常使用时的版本设置,然后去执行writeBytes函数,这个函数的文档解释如下:

  QDataStream &QDataStream::writeBytes(const char *s, uint len)

  Writes the length specifier len and the buffer s to the stream and returns a reference to the stream.

  The len is serialized as a quint32, followed by len bytes from s. Note that the data is not encoded.

也就是说,在写入QString时,还要将文本长度以quint32格式写入,即4个字节,而sizeof(QChar)的字节数为2,所以存入QDataStream中的字节数为:4+2*QString::length()

那么看一下这个程序的输出结果是多少呢?

QByteArray bytes;
QDataStream send(&bytes, QIODevice::WriteOnly);
send.setVersion(QDataStream::Qt_5_9);

QString str1("hello");
QString str2("你好");
int aa=20;
int bb=30;

send<<str1<<str2<<aa<<bb;
qDebug()<<"test:"<<bytes.length();

结果应该为:test: 30。14+8+4+4=30。

2.QDataStream的其它操作方法

在不使用<<操作符时,我们可以写入原生数据,直接调用writeRawData() 方法:

in.writeRawData(fileName,100);
qDebug()<<"print : "<<packData.length();

上面代码输出为print: 100。它没有在前面补充4字节的数据长度。因此在读取时也必须用readRawData()方法。

也可以用writeBytes()方法,如下代码:

in.writeBytes(fileName,100);
qDebug()<<"print : "<<packData.length();

上面代码输出为print: 104。说明它在前面补了4 字节的长度,在读取的时候必须用writeBytes()方法。

总之,QDataStream类非常好用,但在使用的过程中一定要注意数据类型序列化后的字节数。

对于Qt中各种类的使用,我们可以查看帮助文档,能力强的可以看框架的源码,对于初学者来说,可以买一本参考书,以书中的实例为引子,逐步加深学习。我当初用的是这两本教材,给大家参考,书中内容安排的很棒。

进阶参考书:

本文到此结束!觉得还行,顺手点个赞吧。。。

=======================================================

欢迎【关注作者、私信作者】。我们一起交流一起进步。

=======================================================

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值