Qt二进制读取错误在qDatastream中

4
我正在读取一个由传感器产生的二进制文件。我在读取不同精度(32位或64位)的浮点数时遇到了问题。我可以在MATLAB(64位版本)中读取它们,但是在Windows上的Qt(32位版本)却给出错误的值。我可以读取到dtmth(请参考下面的结构)。之后,我得到了baselineInf值。实际上,这个值应该是0。如您所见,我改变了MSB(LittleEndian)。如果我保持BigEndian,则基线为0,但其他值则是错误的。我的桌面是64位的。
我已经检查了字节数,它们是正确的。我认为问题在于机器精度。
QDataStream in(&file);

           in.setByteOrder(QDataStream::LittleEndian);
           params p;

           in >> p.filetype;               
           in >> p.projectid;
           in >> p.datamin;               
           in >> p.dtyear;
           in >> p.dtmth;              
           in >> p.baseline;
           in >> p.startfrequ;

其中p被定义为一个结构体:

    struct params
    {
        quint8 filetype;   
        quint16 projectid;
        double datamin;
        quint16 dtyear;
        quint8 dtmth;    
        float baseline;
        double startfrequ;

    };

我可以在MATLAB中读取它们。我的MATLAB是64位版本,其中我按以下方式读取数据类型:

MATLAB:
        uint8 filetype;   
        uint16 projectid;
        float64 datamin;
        uint16 dtyear;
        uint8 dtmth;    
        float32 baseline;
        float64 startfrequ;

如果我漏掉了任何细节,请告诉我。
编辑:
阅读文件:
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(),
               tr("Raw Files (*.msr);;All files (*.*)"));

           if (!fileName.isEmpty()) {
               qDebug("Attempting to open file..");
               QFile file(fileName);
               if (!file.open(QIODevice::ReadOnly)) {
                   QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
                   return;
               }

               QDataStream in(&file);

提前感谢您。

你也正确地阅读了 datamin 吗? - UmNyobe
再次你好 @UmNyobe。这就是我困惑的地方。我读取了正确数量的字节,两个值都为0。所以我不确定它们是否正确。但是我正确地读取了dtyear。此外,基线值也为0,我得到的是Inf。 - Naresh
文件是否以二进制模式打开?在Windows上,您必须区分二进制和文本模式;文本模式会将输入中的“0x13 0x10”对更改为仅为“0x10”,因此可能会破坏您的数据。 - Angew is no longer proud of SO
我正在使用QFile,默认情况下它假定为二进制。 - Naresh
你尝试过每次切换精度吗? - UmNyobe
1个回答

3
你使用的Qt版本是多少?如果版本高于Qt 4.6,则默认精度为64位,这意味着Qt会尝试将你的32位浮点数读取为64位浮点数。你需要使用in.setFloatingPointPrecision(QDataStream::SinglePrecision);手动设置精度。点击此处查看更多信息。
       in >> p.filetype;               
       in >> p.projectid;
       in >> p.datamin;               
       in >> p.dtyear;
       in >> p.dtmth;    
       in.setFloatingPointPrecision(QDataStream::SinglePrecision);
       in >> p.baseline;
       in.setFloatingPointPrecision(QDataStream::DoublePrecision);
       in >> p.startfrequ;

从您的评论中看来,这似乎是问题所在。实际上,如果您将精度设置为单精度,并尝试读取p.dataminp.startfrequ(64位),那么数据流将将它们读取为32位浮点数。不仅p.datamin将不正确,而且之后的所有值也都会不正确。

首先,要检查我的建议是否有效,请在最后一行之后使用。

      if(in.status() == QDataStream::ReadCorruptData){
            qDebug() << "still doesnt work";
      }

1
我的Qt版本是5.0.1(32位)。在发布这个问题之前,我已经尝试过了。但是在projectid之后,所有的值都是错误的。虽然datamin为0。 - Naresh
Naresh,这证实了这是你的问题。我从未尝试过,但使用我的编辑中的示例代码并告诉我是否正确。我认为这是Qt团队的疯狂行为。 - UmNyobe
嗨@UmNyobe。 我之前也考虑过这个问题。但我以为Qt不会那么愚蠢。但它实际上是。 它解决了这个问题。 我有很多的头信息,比我在这里贴出来的还要多,所以我改了3次,然后才读出正确的值。 有没有什么解决方法?编写自己的函数来更改浮点数和双精度的精度? - Naresh
我能想到的唯一理由是 QDataStream 被设计为写入和读取平台无关的字节流,以序列化对象。但它仍然很烂,因为你基本上需要编写一个自定义包装器来满足你的需求。 - UmNyobe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接