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

Fra*_*ger 25 python file-io

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

floats = [3.14, 2.7, 0.0, -1.0, 1.1]
Run Code Online (Sandbox Code Playgroud)

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

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

Nad*_*mli 40

亚历克斯是绝对正确的,这样做效率更高:

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()
Run Code Online (Sandbox Code Playgroud)

然后像这样读取数组:

input_file = open('file', 'rb')
float_array = array('d')
float_array.fromstring(input_file.read())
Run Code Online (Sandbox Code Playgroud)

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

  • 由于需要 32 位编码,数组中的第一个参数不应该是“f”吗? (3认同)
  • FWIW,事实证明结构答案实际上更快.我做了几个不同的替代方案的分析,结构是最快的相当多.https://gist.github.com/deanmalmgren/fd1714799dc5b5643b87#file-write_profiler-py (2认同)

the*_*met 20

请参阅:Python的struct模块

import struct
s = struct.pack('f'*len(floats), *floats)
f = open('file','wb')
f.write(s)
f.close()
Run Code Online (Sandbox Code Playgroud)

  • 实际上,阵列模块并不快。在这里查看配置文件:https://gist.github.com/deanmalmgren/fd1714799dc5b5643b87#file-write_profiler-py (2认同)

Ale*_*lli 12

标准库中的数组模块可能比每个人都建议的struct模块更适合此任务.用200 MB的数据性能应基本上与阵列更好.

如果您想采用各种选项,请尝试使用类似的方法对系统进行分析


Gra*_*ant 10

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

使用NumPy:

from numpy import array
a = array(floats,'float32')
output_file = open('file', 'wb')
a.tofile(output_file)
output_file.close()
Run Code Online (Sandbox Code Playgroud)

导致20字节的文件.


din*_*ino 6

我在无意中编写 100+ GB 的 csv 文件时遇到了类似的问题。这里的答案非常有帮助,但是为了深入了解,我概述了提到的所有解决方案,然后是一些。所有分析运行均在配备 SSD 的 2014 Macbook Pro 上使用 python 2.7 完成。据我所知,从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
Run Code Online (Sandbox Code Playgroud)


lou*_*uis 6

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

如果要通过 Python 读回该文件,则使用“pickle”模块。这一工具可以以二进制方式读取和写入许多内容。

但问题的提出方式是“IEEE 32 位编码”,听起来该文件将以其他语言读回。在这种情况下,应指定字节顺序。问题是大多数机器都是 x86,采用小端字节顺序,但排名第一的数据处理语言是 Java/JVM,使用大端字节顺序。所以Python的“tofile()”会使用C语言,由于机器是little-endian,C语言使用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)
Run Code Online (Sandbox Code Playgroud)

在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) {}
Run Code Online (Sandbox Code Playgroud)

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

我会使用 numpy 数组和 byteswap

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")
Run Code Online (Sandbox Code Playgroud)

  • @ShanteshwarInde 这是一条合理的信息,也许可以放松一些 (3认同)