我有一个Python中的浮点数值列表:
floats = [3.14, 2.7, 0.0, -1.0, 1.1]
我想使用IEEE 32位编码将这些值写入二进制文件。在Python中最好的方法是什么?我的列表实际上包含约200 MB的数据,因此最好选择“不太慢”的方法。由于有5个值,我只需要20字节的文件作为输出。
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
方法,可以用于读取文件,如果您事先知道项目的数量(例如从文件大小或其他机制)。
for row in myArray:
),然后对row
进行struct.pack
处理。 - IAbstractimport struct
s = struct.pack('f'*len(floats), *floats)
f = open('file','wb')
f.write(s)
f.close()
with
语法。 - Martin Thomadict
以JSON格式写入文件和打包一个3.2M的浮点数表格之间的差异似乎微不足道。也就是说,在这两个操作之间,控制台中的响应似乎没有任何滞后。@AlexMartelli:在我看来,“更好”完全是主观的。这种说法缺乏资格证明。 - IAbstract标准库中的数组模块可能比所有人都在建议的结构体模块更适合这个任务。当处理200 MB的数据时,使用数组的性能应该明显更好。
如果你想尝试各种选项,请在你的系统上使用类似此处的分析工具。
我在无意中写了一个100+ GB的csv文件时遇到了类似的问题。这里的答案非常有帮助,但为了找到问题的根源,我对所有提到的解决方案以及其他方案进行了分析。所有分析都是在使用Python 2.7的2014年Macbook Pro上进行的。从我的观察来看,从性能角度来看,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
我的“答案”实际上是对各种答案的评论。由于我没有50个声望,因此无法发表评论。
如果文件将由Python读取,则使用“pickle”模块。这个工具可以读写许多二进制文件。
但是,问题的提问方式是说“IEEE 32位编码”,这听起来像是文件将在其他语言中被读取。在这种情况下,应指定字节顺序。问题是大多数机器都是x86,采用小端字节顺序,而第一数据处理语言是Java / JVM,采用大端字节顺序。因此,Python“tofile()”将使用C,由于机器是小端,所以使用小端,然后Java / JVM上的数据处理代码将使用大端进行解码,从而导致错误。
要使用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)
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")