转载: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。