【问题标题】:Qt binary reading error in qDatastreamqDatastream 中的 Qt 二进制读取错误
【发布时间】:2013-04-09 08:38:39
【问题描述】:

我正在读取由传感器生成的二进制文件。我在读取具有不同精度(32 或 64)的浮点数时遇到问题。我可以在 MATLAB(64 位版本)中读取它们,但 Qt(Windows 上的 32 位版本)给出了错误的值。我可以读到dtmth(请参考下面的结构)。在它之后,我得到了 Inf 的值 baseline。这个值实际上是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。这就是我感到困惑的地方。我正在读取正确的字节数,两个值都是 0。所以我不确定它们是否正确。但是后来我正确地阅读了 dtyear 。此外,baseline 的值也是 0,我得到的是 Inf。
  • file 是否以二进制模式打开?在 Windows 上,您必须区分二进制和文本模式;文本模式在输入时将 0x13 0x10 对更改为 0x10,因此它可能会损坏您的数据。
  • 我使用的是 QFile,它默认采用二进制文件。 (问题已更新)
  • 你有没有试过每次都切换精度??

标签: c++ qt binary precision


【解决方案1】:

您使用的是哪个版本的 Qt?如果版本优于 Qt 4.6,则默认精度为 64 位,which means Qt will try to read your float 32 as a float 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";
      }

【讨论】:

  • 我的 Qt 是 5.0.1(32 位)。在发布这个问题之前,我已经尝试过了。但是在 projectid 之后所有的值都是错误的。虽然 datamin 是 0。
  • Naresh,它确认这是您的问题。我从未尝试过,但在我的编辑中使用示例代码并告诉我它是否正确。我相信这对 qt 家伙来说是疯狂的。
  • 嗨@UmNyobe。我其实是这么想的。但我认为 Qt 不会那么愚蠢。但实际上是。它解决了这个问题。实际上,我的标题信息比我放在这里的要多得多,所以我必须更改 3 次,然后才能读取正确的值。有解决办法吗?编写自己的函数来改变浮点数和双精度数的精度?
  • 我想到的唯一原因是 QDataStream 旨在编写和读取与平台无关的字节流以用于序列化对象。仍然很糟糕,因为您基本上需要编写您所说的,一个自定义包装器。