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

本文详细解析了Qt中QDataStream处理QString时的常见问题,包括数据长度的计算方法及如何正确使用writeBytes等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

进阶参考书:

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

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

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

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

### QDataStream 数据流类型及其使用方法 #### 1. 构造函数与初始化 `QDataStream` 提供多个构造函数来创建数据流对象。最常用的两种方式是通过 `QIODevice` 或者 `QByteArray` 来初始化: - 默认构造函数用于创建未绑定到任何设备的数据流实例。 - 可以直接传入一个 `QIODevice*` 参数给构造函数,从而将该数据流绑定至指定的I/O设备上。 ```cpp // 创建默认的数据流对象 QDataStream stream; // 绑定到文件进行读写操作 QFile file("example.dat"); if (file.open(QIODevice::ReadWrite)) { QDataStream stream(&file); } ``` [^2] #### 2. 设置版本号 为了确保不同平台间兼容性和向前向后的兼容性,在实际应用中通常会设置 `QDataStream` 版本号: ```cpp stream.setVersion(QDataStream::Qt_5_10); // 设置为特定版本 ``` [^1] #### 3. 插入器 (`<<`) 和提器 (`>>`) `QDataStream` 重载了 C++ 中的标准输入输出运算符 `< <` 和 `> >` ,使得可以非常直观地执行序列化和反序列化的操作。这不仅限于内置的基础数据类型(如整数、浮点数),还包括字符串和其他复杂结构体或类的对象。 ```cpp int number = 42; QString text = "Hello, world!"; double value = 3.14; // 序列化过程 stream << number << text << value; // 反序列化过程 int readNumber; QString readText; double readValue; stream >> readNumber >> readText >> readValue; ``` [^3] #### 4. 关联不同的 IO 设备 除了常见的文件外,`QDataStream` 还能与其他类型的 `QIODevice` 子类配合工作,比如内存缓冲区(`QBuffer`)、网络套接字(`QTcpSocket`)等,实现了更加灵活多样的应用场景下的数据交换功能。 ```cpp QByteArray byteArray; QDataStream byteStream(&byteArray); // 向 QByteArray 写入数据 byteStream << QString("This is a test"); // 从 QByteArray 读数据 QString str; byteStream >> str; qDebug() << str; // 输出: This is a test ``` [^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值