QT中QDataStream二进制数据读写的实现,+ 坑

目录

QT中QDataStream二进制数据读写的实现

QDataStream 的坑

QDataStream获取的数据总是有问题  :数据类型错误QDataStream获取的数据总是有问题_Kelvin_Ngan的博客-CSDN博客

QT 使用QDataStream时遇到的坑

【Qt @bug】QDataStream反序列化失败导致程序奔溃

Qt 使用QDataStream保存文件时的坑

使用QDataStream写入原始二进制数据的几点注意事项

---------------------------------------------------------------

最后才发现dts<<QString或者Qbytearry 会自动在其前面加上4字节大小。

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

使用QDataStream写入原始二进制数据的几点注意事项

原文链接:QDataStream使用注意事项

    1.不要直接把QByteArray直接 < < << << 进QDataStream,他会在最前面自动添加长度信息;

      如果要写 原始 QByteArray数据可以使用 writeRawData(char*, int)方法,第一个参数为char数组,第二个参数为长度。

    2.将QDataStream对象所关联的QByteArray对象清空后,用QDataStream对象去继续写入数据到QByteArray对象中,结果并不如预期那样从位置0开始写入,而是从之前的位置开始写入,前面的数据呈现未定义状态(QBuffer有一样的问题)。

      可以用局部对象的方法解决,将QDataStream对象设为局部对象,这样每次执行函数完成后该对象会自动销毁,再次执行该函数就是新的QDataStream对象,不会出现上述问题(新的QDataStream对象可以继续关联全局的QByteArray对象)。

    3.QDataStream写浮点数据的默认精度是DoublePrecision(64bit),需要设置

SinglePrecision(32bit)

    4.0x0A是个特殊的字符,翻译为\n,代表行结束符,在win32上会转换为’\r\n’,二进制表示为0x0D 0x0A,会多出一个字节。

      解决办法为以二进制读写方式打开文件,fopen(path,‘wb’); 在QT中就是不要以QIODevice::Text打开文件。

————————————————
版权声明:本文为CSDN博主「工科南」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/I_am_mengxinxin/article/details/117462119

Qt 使用QDataStream保存文件时的坑

1、问题

最近一直在用阿里的语音合成功能,已wav格式获取响应内容保存下来的音频文件竟然无法播放。
在这里插入图片描述

保存音频流的失败代码如下:

    QByteArray ba = reply->readAll();
    QFile file("C:/Users/congt/Downloads/demo.wav");
    file.open(QIODevice::WriteOnly);

 
    QDataStream out(&file);
    out << ba;

 
    file.close();

本来我以为是因为在我保存wav文件时没有设置文件格式的问题,但是!

    保存下来的wav文件

demo.wav

    原来的文件

response.wav

保存后的文件竟然大了4个字节????

2、解决方法

同时使用 QFileQDataStream会在文件头(自动?)写入四个字节的 magic number

使用file.write()代替即可。代码改为如下形式。

    QFile file("C:/Users/congt/Downloads/demo.wav");
    file.open(QIODevice::WriteOnly);

 
    file.write(ba);

 
    file.close();

————————————————
版权声明:本文为CSDN博主「丛继晔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40448140/article/details/100942703

QT 使用QDataStream写入QByteArray数据时遇到的坑

在做Qt的序列化和反序列化,粘包问题解决的时候,需要自己定义消息的格式。粘包问题解决后,但是发现消息中多了点东西。有问题,先打印出来看看,用QByteArray中的toHex打印16进制是比较好的做法。
起因:

一、起因

每条消息 = 总长度 + 消息号 + 内容

【Qt @bug】QDataStream反序列化失败导致程序奔溃

【解决说明】

借助QVariant类型, 即先将数据反序列称为QVariant,在将QVariant转为自定义的数据;

关键点 如下:

QVariant与自定义数据转换

利用qRegisterMetaTypeStreamOperators对自定义结构体进行注册

【Qt @bug】QDataStream反序列化失败导致程序奔溃_qdatastream >>_huai0321的博客-CSDN博客

QT 使用QDataStream时遇到的坑

使用QT与Go服务端进行通信,每个数据包大小都以约定好结构为 len | feature| compress| data

结果使用QDatastream进行添加数据时发现data数据开头有乱码,比如发送12345结果服务端接收为

QT 发送代码如下:

        QByteArray socket_packdata=QString("12345").toLatin1();
        bool isCompress=false;
        QByteArray senddata;
        QDataStream dts(&senddata, QIODevice::WriteOnly);
        dts<<((uint64_t)0)<<((uint8_t)123)<<(bool)false<<socket_packdata;
        dts.device()->seek(0);
        dts<<((uint64_t)senddata.size());
        write(senddata);
        flush();

仔细看没有问题,变改了服务端代码,让其去除data前面四个字节,结果显示正常。

后经查询发觉可能是QBytearry会自动带上其大小,便使用Char * 指针往后移四位,结果服务器接收数据少四位。

最后才发现 dts<<QString或者Qbytearry 会自动在其前面加上4字节大小

只需改为

senddata +=socket_packdata 不使用 QDataStream 中的<< 即可

切记切记。
————————————————
版权声明:本文为CSDN博主「月下独奏」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/d7185540/article/details/81133130

QT中QDataStream二进制数据读写的实现


本文主要介绍了QT中QDataStream二进制数据读写的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Qt中的QDataStream类为我们的程序提供了读写二进制数据的能力。一个数据流如果是二进制编码的数据流,那么它肯定是与计算机的操作系统、CPU或者字节序无关的。例如,一个数据流是在一个运行Windows系统的PC机上被写入的,那么它照样可以在一台运行Solaris的Sun SPARC的机器上被读取出来。同样,我们也可以使用QDataStream去读写原生的未编码的二进制数据。

QDataStream类实现了序列化C++的基本数据类型的功能,比如char,short,int,char* 等等。如果要序列化更复杂的数据类型,可以将复杂数据类型分解成独立的基本数据类型分别进行序列化。

一个数据流往往需要一个QIODevice配合使用。因为QIODevice代表了一个可以从中读取数据或向其写入数据的输入输出设备。我们最常常见的QFile文件类就是一种QIODevice。下面我们先分别看一个使用QDataStream进行二进制数据读写的例子。

write binary data to a stream:

QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);   // we will serialize the data into the file
out << QString("the answer is");   // serialize a string
out << (qint32)42;        // serialize an integer

read binary data from a stream:

QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);    // read the data serialized from the file
QString str;
qint32 a;
in >> str >> a;           // extract "the answer is" and 42

每一项被写入的数据,都是按一种预定义的二进制格式写入的,改格式取决于具体每一项的类型。而QDataStream支持的类型包括QBrush,QColor,QDateTime等等。

特别注意,对应整数来说,在写入时最好转换成Qt中的某种整数类型,读取时也读取为同样的Qt整数类型。这可以确保得到正确大小的整数并且可以屏蔽掉不同编译器和平台之间的差异。举个栗子,对于一个char* 字符串来说,先写入一个32-bit的整数值,该值就是字符串的长度,包括'\0',紧接着是字符串中 的每一个字符,包括'\0'。当读取时,也是这样操作,写读取4字节创建出一个32-bit的字符串长度值,然后再根据创建出的长度值读取出相应个数的字符,包括'\0'。

版本

QDataStream的二进制格式从Qt1.0就开始形成了,很有可能在将来继续进化已反应Qt的变化。当操作复杂数据类型时,我们就要确保读取和写入时的QDataStream版本是一样的。如果你需要向前和向后兼容,可以在代码中使用硬编码指定流的版本号:
    
stream.setVersion(QDataStream::Qt_4_0);

如果你正在创建一种新的二进制数据格式,比如作为你的应用程序创建的文件的格式,你可以使用QDataStream以一种可移植的格式去写入这些数据。典型情况下,你可能会在文件头写入一个简短的幻数字符串和一个版本数字,来用于将来扩展。例如:

QFile file("file.xxx");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
 
// Write a header with a "magic number" and a version
out << (quint32)0xA0B0C0D0;
out << (qint32)123;
 
out.setVersion(QDataStream::Qt_4_0);
 
// Write the data
out << lots_of_interesting_data;

那么,我们就可以以下面这种方式来读取:

QFile file("file.xxx");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
 
// Read and check the header
quint32 magic;
in >> magic;
if (magic != 0xA0B0C0D0)
    return XXX_BAD_FILE_FORMAT;
 
// Read the version
qint32 version;
in >> version;
if (version < 100)
    return XXX_BAD_FILE_TOO_OLD;
if (version > 123)
    return XXX_BAD_FILE_TOO_NEW;
 
if (version <= 110)
    in.setVersion(QDataStream::Qt_3_2);
else
    in.setVersion(QDataStream::Qt_4_0);
 
// Read the data
in >> lots_of_interesting_data;
if (version >= 120)
    in >> data_new_in_XXX_version_1_2;
in >> other_interesting_data;

同时,还可以在序列化数据时指定一个字节序。默认情况下是big endian。除非特殊需求,我们一个建议保持这个设置的默认值,不做修改。

读写原生二进制数据

有时,我们希望直接从data stream里读取原生的二进制数据。此时,可以使用readRawData() 将数据读入一个预先分配好的char*;同样的数据也可以使用writeRawData() 函数写入data stream。但要记住,使用这种方式的话,要由你自己进行所有数据的编码和解码。于此类似的另外两个函数是readBytes() 和 writeBytes()。这两个函数与上面的Raw版本相比,区别主要是:readBytes() 先读取一个quint32值,该值被当做将要读取的数据的长度,然后读取相应字节的数据到预先定义好的char*中;writeBytes() 也同理,先写入一个quint32的数据长度值,紧接着写入相应数据。同样,使用这两个函数,所以数据的编码和解码要有我们自己负责。注意,readBytes() 不需要我们事先分配好内存, 而readRawData() 需要我们事先分配好内存。

读写Qt集合类和其他Qt类

Qt的常见集合类也可以使用QDataStream进行序列化,这包括QList,QLinkedList,QVector,QSet,QHash和QMap。不过,序列化这些类的流操作符不是这个类的成员函数而已。同理,读写Qt中的其他类型,比如QImage,也是可以的。

使用事务

当在一个异步的设备上读取数据时,数据块可以在任意的时间点上到来。所以,为了应对这种情况,QDataStream提供了一个事务机制来确保原子性的完成一系列的流操作符。例如,你可以在操作socket时,在相应readyRead() 的槽函数中,使用事务来完成不完整的数据读取。

in.startTransaction();
QString str;
qint32 a;
in >> str >> a; // try to read packet atomically
 
if (!in.commitTransaction())
    return;     // wait for more data

如果没有完整的数据包到来,commitTransaction() 会返回false,并将stream重置为初始状态,然后,等待更多数据的到来。

下面给出一个简单的测试程序:

#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QFile>
#include <QVector>
#include <QMap>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    //write
    QFile file("test.dat");
    if (!file.open(QIODevice::ReadWrite))
    {
        qDebug() << "open file failed";
        return 0;
    }
    QDataStream ds(&file);
    const char *wstr = "hello-world";
    quint32 wi = 1234;
    double wd = 1.1;
    float wf = 2.2f;
    QVector<int> wvector;
    wvector.push_back(1);
    wvector.push_back(2);
    wvector.push_back(3);
    QMap<int,int> wmap;
    wmap.insert(4, 4);
    wmap.insert(5, 5);
    wmap.insert(6, 6);
    ds << wstr;
    ds << wi;
    ds << wd;
    ds << wf;
    ds << wvector;
    ds << wmap;
    ds.writeBytes("file end ", qstrlen("file end "));
    ds.writeRawData("really end", qstrlen("really end"));
 
    //read
    file.seek(0);
    char *rstr;
    quint32 ri;
    double rd;
    float rf;
    QVector<int> rvector;
    QMap<int, int> rmap;
    char *rbytes;
    uint len;
    char *rraw = new char[100]{0};
    int rlen;
    ds >> rstr;
    ds >> ri;
    ds >> rd;
    ds >> rf;
    ds >> rvector;
    ds >> rmap;
    ds.readBytes(rbytes, len);
    ds.readRawData(rraw, rlen);
    qDebug() << rstr;
    qDebug() << ri;
    qDebug() << rd;
    qDebug() << rf;
    qDebug() << rvector;
    qDebug() << rmap;
    qDebug() << rbytes;
    qDebug() << rraw;
 
    return a.exec();
}

到此这篇关于QT中QDataStream二进制数据读写的实现的文章就介绍到这了,更多相关QT QDataStream二进制数据读写内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

  https://www.jb51.net/article/260178.htm

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值