【问题标题】:What is the best method to read a double from a Binary file created in C?从用 C 语言创建的二进制文件中读取双精度的最佳方法是什么?
【发布时间】:2009-03-10 18:13:05
【问题描述】:

C 程序将连续的双精度值输出到二进制文件中。我希望将它们读入 Python。我尝试使用struct.unpack('d',f.read(8))

编辑: 我在C中使用以下内容编写了一个随机双数

r = drand48();
fwrite((void*)&r, sizeof(double), 1, data);

错误现已修复,但我无法读取第一个值。对于全 0.000.. 数字,它读取为 3.90798504668055,但其余的都很好。

【问题讨论】:

  • 它可能与不正确的 endiness 相关联(首先是最不重要的字节)。显示您要读取的字节数。
  • 对不起。我几乎解决了这个问题,所以我将其标记为已回答。我希望看到第一个数字被正确读取。
  • 您能否提供文件前 40 个字节的转储以及您当前用于读取它的代码?
  • 嘿,我已经在这里上传了文件:s000.tinyupload.com/?file_id=70513514505809549127
  • 这些是 0 到 1 之间的双精度数

标签: python c double


【解决方案1】:

我认为您实际上是在正确读取数字,但对显示感到困惑。当我从您提供的文件中读取数字时,我得到“3.907985046680551e-14” - 这几乎但不完全为零(扩展形式为 0.000000000000039)。我怀疑你的 C 代码打印的精度比 python 低。

[编辑] 我刚刚尝试在 C 中读取文件,我得到了相同的结果(虽然精度稍低:3.90799e-14)(使用 printf("%g", val)),所以我认为如果此值不正确,则发生在写入端,而不是读取端。

【讨论】:

  • 嘿,布赖恩,你成功了。我懒得扩展它:(。精度是2个不同值的原因。谢谢你的帮助。
【解决方案2】:

能否请您详细说明“没用”?命令崩溃了吗?数据出来错了吗?究竟发生了什么?

如果命令崩溃:

  • 请分享命令的错误输出

如果数据出现错误:

  • 创建和读取数据的系统是否具有相同的字节序?如果一个是大端,另一个是小端,那么您需要在格式字符串中指定字节序转换。

  • 如果两台计算机的字节序相同,那么数据是如何写入文件的,究竟?你知道吗?如果你这样做了,那么写入文件的值是什么,你得到的错误值是什么?

【讨论】:

    【解决方案3】:

    首先,你试过pickle吗? 还没有人展示任何 Python 代码...这是一些用于在 python 中读取二进制文件的代码:

    import Numeric as N
    import array
    filename = "tmp.bin"
    file = open(filename, mode='rb')
    binvalues = array.array('f')
    binvalues.read(file, num_lon * num_lat) 
    data = N.array(binvalues, typecode=N.Float)   
    
    file.close()
    

    这里的 f 指定单精度、4 字节浮点数。找到每个条目的数据大小并使用它。

    对于非二进制数据,您可以执行以下简单操作:

       tmp=[]
       for line in open("data.dat"):
                    tmp.append(float(line))
    

    【讨论】:

    • 嘿亚历克斯,我确实尝试过泡菜,但对于我的问题,我不能保证所有值都是双打。它们可以是整数、浮点数或双精度数。我只知道要读取的值的位置和类型。不过感谢您的帮助:)
    【解决方案4】:
    • f.read(8) 可能返回少于 8 个字节
    • 数据可能有不同的对齐方式和/或字节序:

      >>> for c in '@=<>':
      ...     print repr(struct.pack(c+'d', -1.05))
      ...
      '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
      '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
      '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
      '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd'
      >>> struct.unpack('<d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd')
      (-6.0659880001157799e+066,)
      >>> struct.unpack('>d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd')
      (-1.05,)
      

    【讨论】:

      【解决方案5】:

      最好的方法是使用 ASCII 文本文件:

      0.0
      3.1416
      3.90798504668055

      因为它是可移植的,并且在一定程度上可以与任何类型的浮点实现一起使用。

      double 的内存地址读取原始二进制数据根本不可移植,并且在某些不同的实现中必然会失败。

      您当然可以使用二进制格式来保持紧凑性,但是以这种格式编写的可移植 C 函数看起来根本不像您的 sn-p。

      至少,代码应该被一系列 ifs/ifdefs 包围,检查当前机器使用的doubles 的内存表示是否与 Python 解释器预期的完全匹配。

      编写这样的代码会很困难,这就是为什么我建议使用简单、干净、可移植和人类可读的 ASCII 文本解决方案。

      这将是我的对“最佳”的定义。

      【讨论】:

      • 嗨 Aib,我希望我能做到这一点,但它是一个内存转储,我无法控制它的导出方式。我在 unpack 方面取得了很好的成功,但由于某种原因没有正确读取第一个 Double。
      • 我猜到了,但仍然想为未来的读者说明我的观点。很高兴您解决了您的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多