【问题标题】:How to output list of floats to a binary file in Python如何在 Python 中将浮点数列表输出到二进制文件
【发布时间】:2009-04-30 16:35:43
【问题描述】:

我有一个 Python 中的浮点值列表:

floats = [3.14, 2.7, 0.0, -1.0, 1.1]

我想使用 IEEE 32 位编码将这些值写入二进制文件。在 Python 中执行此操作的最佳方法是什么?我的列表实际上包含大约 200 MB 的数据,所以最好是“不要太慢”。

由于有 5 个值,我只想要一个 20 字节的文件作为输出。

【问题讨论】:

  • 您的数组在数字之间缺少逗号。

标签: python file-io


【解决方案1】:

Alex 完全正确,这样做效率更高:

from array import array
output_file = open('file', 'wb')
float_array = array('d', [3.14, 2.7, 0.0, -1.0, 1.1])
float_array.tofile(output_file)
output_file.close()

然后像这样读取数组:

input_file = open('file', 'rb')
float_array = array('d')
float_array.fromstring(input_file.read())

array.array 对象也有一个 .fromfile 方法,如果您事先知道项目的数量(例如,根据文件大小或其他机制),则可用于读取文件

【讨论】:

  • 由于要求 32 位编码,数组中的第一个参数不应该是“f”吗?
  • FWIW,事实证明结构答案实际上更快。我对几种不同的替代方案进行了一些分析,而 struct 是最快的。 gist.github.com/deanmalmgren/…
  • @user-2147482637:我有一个二维浮点数组。我正在迭代元素 (for row in myArray:) 然后 struct.packing row
【解决方案2】:

见:Python's struct module

import struct
s = struct.pack('f'*len(floats), *floats)
f = open('file','wb')
f.write(s)
f.close()

【讨论】:

  • 其实我现在就是这么做的。我只是认为必须有更好的方法。
  • 还有一种更好的方法——数组模块。有关所有详细信息,请参阅docs.python.org/library/array.html
  • 您应该使用with 语法。
  • 数组模块实际上并不快。在此处查看分析:gist.github.com/deanmalmgren/…
  • 将 2 dicts 写入 JSON (22K) 文件和打包 3.2M 浮点数表的差异似乎可以忽略不计。也就是说,控制台中的响应似乎在这两个操作之间根本没有滞后。 @AlexMartelli:恕我直言,“更好”是完全主观的。该断言缺乏资格。
【解决方案3】:

标准库中的array模块可能比大家推荐的struct模块更适合这个任务。 200 MB 数据的性能应该大大使用数组更好。

如果您想采用多种选择,请尝试使用 something like this 在您的系统上进行分析

【讨论】:

    【解决方案4】:

    我不确定NumPy 将如何比较您的应用程序的性能,但它可能值得研究。

    使用NumPy

    from numpy import array
    a = array(floats,'float32')
    output_file = open('file', 'wb')
    a.tofile(output_file)
    output_file.close()
    

    也会产生一个 20 字节的文件。

    【讨论】:

    【解决方案5】:

    我无意中编写了一个 100+ GB 的 csv 文件时遇到了类似的问题。这里的答案非常有帮助,但要深入了解,I profiled all of the solutions mentioned and then some。所有的分析运行都是在 2014 年 Macbook Pro 上使用 python 2.7 和 SSD 完成的。就我所见,struct 方法从性能的角度来看绝对是最快的:

    6.465 seconds print_approach    print list of floats
    4.621 seconds csv_approach      write csv file
    4.819 seconds csvgz_approach    compress csv output using gzip
    0.374 seconds array_approach    array.array.tofile
    0.238 seconds numpy_approach    numpy.array.tofile
    0.178 seconds struct_approach   struct.pack method
    

    【讨论】:

      【解决方案6】:

      我的“答案”实际上是对各种答案的评论。我没有 50 声望,所以无法发表评论。

      如果要由 Python 读回文件,则使用“pickle”模块。这个工具可以用二进制读写很多东西。

      但问题的方式是“IEEE 32 位编码”,听起来文件会以其他语言读回。在这种情况下,应指定字节顺序。问题是大多数机器都是 x86,采用 little-endian 字节顺序,但排名第一的数据处理语言是 Java/JVM,使用 big-endian 字节顺序。所以Python的tofile()会使用C,由于机器是little-endian,所以使用little endian,然后Java/JVM上的数据处理代码会使用big endian进行解码,导致报错。

      使用 JVM:

      # convert to bytes, BIG endian, for use by Java
      import struct
      f = [3.14, 2.7, 0.0, -1.0, 1.1]
      b = struct.pack('>'+'f'*len(f), *f)
      
      with open("f.bin", "wb") as file:
          file.write(b)
      

      在 Java 方面:

      try(var stream = new DataInputStream(new FileInputStream("f.bin")))
      {
          for(int i = 0; i < 5; i++)
              System.out.println(stream.readFloat());
      }
      catch(Exception ex) {}
      

      现在的问题是 Python 'f'*len(f) 代码 - 希望解释器实际上不会创建超长的“ffffff...”字符串。

      我会使用 numpy 数组和字节交换

      import numpy, sys
      f = numpy.array([3.14, 2.7, 0.0, -1.0, 1.1], dtype=numpy.float32)
      
      if sys.byteorder == "little":
          f.byteswap().tofile("f.bin") # using BIG endian, for use by Java
      else:
          f.tofile("f.bin")
      

      【讨论】:

      • 请避免写我为什么要写答案而不是评论,如果您阅读了如何写答案并且您的答案满足所有参数,那么只需回答
      • @ShanteshwarInde 这是一条合理的信息,也许可以放松一下
      【解决方案7】:

      【讨论】:

        【解决方案8】:

        struct.pack() 看起来像你需要的。

        http://docs.python.org/library/struct.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-05
          • 2014-06-10
          • 2013-10-09
          • 2015-12-02
          • 1970-01-01
          • 2012-10-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多