如何在 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.pack
ing 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 dict
s 写入 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从二进制文件中读取32位带符号的ieee 754浮点?