如何在 Python 中将浮点数列表输出到二进制文件

Posted

技术标签:

【中文标题】如何在 Python 中将浮点数列表输出到二进制文件【英文标题】:How to output list of floats to a binary file in 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 字节的文件作为输出。

【问题讨论】:

您的数组在数字之间缺少逗号。 【参考方案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 字节的文件。

【讨论】:

不如使用 struct 快。在此处查看简介gist.github.com/deanmalmgren/…【参考方案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】:

看看struct.pack_into

【讨论】:

【参考方案8】:

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

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

【讨论】:

以上是关于如何在 Python 中将浮点数列表输出到二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

在python中将字符串保存到二进制文件

如何在 Python 中将字节数转换为二进制数?

如何在 Python 中将负指数数转换为十进制数?

用python从二进制文件中读取32位带符号的ieee 754浮点?

python使用np.linspace函数生成均匀的浮点数列表实战:生成浮点数列表生成浮点数列表(指定是否包含末尾值)

如何在 Python 3 中将原始十六进制字节写入标准输出?