QDataStream处理数组或字符串

转载:https://blog.csdn.net/tom06/article/details/80732571


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

QDataStream处理char数组

考虑一下通过QDataStream将char数组输入到QByteArray中,一般网络报文序列化可能会遇到。

1. 问题的产生
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_10);

in<<fileName;
qDebug()<<"print : "<<packData.length();
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

以上代码的输出结果是print : 5;

通过<<输入时,会先放4个字节,作为长度;因为fileName初始化为0,QDataStream取第一个字节时,就遇到了0,它认为已经结束了,所以长度是5。

memset(fileName,1,100);
...
in<<fileName;
qDebug()<<"print : "<<packData.length();
 
 
  • 1
  • 2
  • 3
  • 4

要是fileName没有结束符,其实总长度应该是4+100,但是结果却是106。也是不正确的。

2. 使用QDataStream::writeRawData方法

不能用操作符,就直接调方法。

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

以上代码的输出刚好是100,它没有在前面补4字节的长度;读的时候应该用QDataStream::readRawData

3. 使用QDataStream::writeBytes方法
in.writeBytes(fileName,100);
qDebug()<<"print : "<<packData.length();
 
 
  • 1
  • 2

以上代码的输出是104,说明它在前面补了4字节的长度;

读的时候应该用QDataStream::readBytes(char *&s, uint &l)

但注意形参s是指针的引用,在方法内部会分配内存,所以在外部我们不需要分配内存,但要及时使用delete[]释放。


如果QDataStream是ReadWrite模式的

QDataStream既可用于读入又可用于读出,那么存在一种情况,把字符串读入到ByteArray中,然后又立即输出到另一个空字符串中。

QByteArray tmpBytes;
QDataStream dataRWStream(&tmpBytes,QIODevice::ReadWrite);
dataRWStream.setByteOrder(QDataStream::BigEndian);
dataRWStream.setVersion(QDataStream::Qt_5_10);

char dataArrayOne[10];
memset(dataArrayOne,0,10);
QString strData("this");
memcpy(dataArrayOne,strData.toStdString().c_str(),strData.length());

dataRWStream.writeRawData(dataArrayOne,10);

char dataArrayTwo[10];
memset(dataArrayTwo,0,10);
// 先注释这一句
//dataRWStream.device()->seek(0);
dataRWStream.readRawData(dataArrayTwo,10);
qDebug()<<"test :"<<dataArrayTwo;
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上例的执行结果输出为空的;也就是说dataArrayTwo中没有数据。取消注释dataRWStream.device()->seek(0);这一句,输出“this”,达到目的。

为什么呢,本例中QDataStream构造函数的参数,QByteArray不是继承自QIODevice,QDataStream在处理时会创建一个QBuffer,QBuffer是继承自QIODevice的,QIODevice都有一个文件指针,指向当前位置,读入字符串后,指针指向第11个地址,输出时仍然从第11个地址开始,当然没有数据了,此时应当回调到第0个地址上,才能读取到数据;

而 dataRWStream.device()->seek(0);
 
 
  • 1

就是用于重置指针位置的。


QDataStream读入QString需要注意的

QString在QT中以Unicode编码,一个字符占两个字节。

QByteArray tmpBytes;
QDataStream dataRWStream(&tmpBytes,QIODevice::ReadWrite);
dataRWStream.setByteOrder(QDataStream::BigEndian);
dataRWStream.setVersion(QDataStream::Qt_5_10);


QString strData("123456789");
dataRWStream<<strData;

qDebug()<<"test :"<<tmpBytes.length();
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

将strData通过QDataStream输入tmpBytes,tmpBytes的长度本应该是9+4(填入4字节保存长度)=13的;但执行结果却是22。因为QString的编码规则,所以应当是字符个数9*2+4(填入4字节保存长度)=22。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QDataStream提供了一些方法可以读取指定长度的数据,例如QDataStream::readRawData()函数可以读取指定长度的原始字节数据,QDataStream::readBytes()函数可以读取指定长度的字符串数据,QDataStream::readFloat()函数可以读取一个float类型的数据等。你可以通过组合使用这些函数来读取数组中的指定部分数据,实现读取指定范围的数据。 下面是一个读取指定范围数据的示例代码: ```c++ quint8 byteArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; QByteArray byteData = QByteArray::fromRawData(reinterpret_cast<char*>(byteArray), 10); QDataStream dataStream(&byteData, QIODevice::ReadOnly); quint8 buffer[4]; dataStream.readRawData(reinterpret_cast<char*>(buffer), 4); // 读取byteArray中的第1到第4个字节 float floatValue; dataStream.readRawData(reinterpret_cast<char*>(&floatValue), 4); // 读取byteArray中的第5到第8个字节,转换为float类型的数据 ``` 在上面的代码中,首先将一个长度为10的quint8数组转换为QByteArray对象,然后使用QDataStream来读取指定的数据。其中,第一行代码创建了一个长度为4的quint8数组buffer,第二行代码使用QDataStream::readRawData()函数读取byteData中的前4个字节数据,存储到buffer数组中;第三行代码使用同样的方式读取byteData中的第5到第8个字节,并将其转换为float类型的数据,存储到floatValue中。 需要注意的是,QDataStream类是基于流的数据读操作,所以在读数据时需要保证数据的顺序和格式一致,否则可能会导致数据的解析错误或类型转换错误。在读数据时,应该先了解数据的结构和格式,然后按照相应的顺序和格式进行读操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值