用python读取二进制文件
Posted
技术标签:
【中文标题】用python读取二进制文件【英文标题】:Reading a binary file with python 【发布时间】:2012-02-01 09:15:33 【问题描述】:我发现用 Python 读取二进制文件特别困难。你能帮我个忙吗? 我需要阅读这个文件,它在 Fortran 90 中很容易被阅读
int*4 n_particles, n_groups
real*4 group_id(n_particles)
read (*) n_particles, n_groups
read (*) (group_id(j),j=1,n_particles)
具体来说,文件格式是:
Bytes 1-4 -- The integer 8.
Bytes 5-8 -- The number of particles, N.
Bytes 9-12 -- The number of groups.
Bytes 13-16 -- The integer 8.
Bytes 17-20 -- The integer 4*N.
Next many bytes -- The group ID numbers for all the particles.
Last 4 bytes -- The integer 4*N.
如何使用 Python 阅读此内容?我尝试了一切,但从未奏效。我有没有机会在 python 中使用 f90 程序,读取这个二进制文件,然后保存我需要使用的数据?
【问题讨论】:
这个文件是由 Fortran 程序编写的吗?如果是这样,它是如何写入的,因为默认情况下,Fortran 在它写入文件的每条记录之前添加额外的数据。读取数据时可能需要注意这一点。 请忽略我之前的评论,整数 8 和 4*N 显然是这个附加数据。 另外,请参阅问题的答案reading binary file in python。 Numpy 的fromfile
函数可以轻松读取二进制文件。我推荐它。
...并始终注意您的字节序,尤其是。在不同制造商的计算机之间移植时。
【参考方案1】:
读取二进制文件内容如下:
with open(fileName, mode='rb') as file: # b is important -> binary
fileContent = file.read()
然后使用struct.unpack“解压”二进制数据:
起始字节:struct.unpack("iiiii", fileContent[:20])
正文:忽略标题字节和尾随字节(= 24);剩下的部分构成正文,要知道正文中的字节数,进行整数除以 4;得到的商乘以字符串'i'
,为解包方法创建正确的格式:
struct.unpack("i" * ((len(fileContent) -24) // 4), fileContent[20:-4])
结束字节:struct.unpack("i", fileContent[-4:])
【讨论】:
你能看看这个其他帖子吗? ***.com/questions/8092469/… ...我再次读取另一个二进制文件,但在这种情况下,我不知道详细的字节结构。例如,我发现有时会有整数 8。但是,使用 IDL 读取这些数据非常简单。我可以用 python 做同样的事情吗? 请说明(在其他帖子中,而不是此处)您对发布的答案和 cmets 不满意的原因。也许您还应该更新问题以提供更多详细信息...我会在更新时查看它。 如果您需要将解压缩的 char[] 转换为字符串,请参阅this 答案。import struct
为什么要除以 4?【参考方案2】:
一般来说,我建议您为此考虑使用 Python 的 struct 模块。它是 Python 的标准,应该很容易将您的问题规范转换为适合 struct.unpack()
的格式字符串。
请注意,如果字段之间/周围存在“不可见”填充,您需要弄清楚这一点并将其包含在 unpack()
调用中,否则您将读取错误的位。
读取文件的内容以便解压非常简单:
import struct
data = open("from_fortran.bin", "rb").read()
(eight, N) = struct.unpack("@II", data)
这将解包前两个字段,假设它们从文件的最开头开始(没有填充或无关数据),并且还假设本机字节顺序(@
符号)。格式化字符串中的I
s 表示“无符号整数,32 位”。
【讨论】:
好的,但我什至不知道如何读取文件的字节。根据我的问题,如何从字节 5 到 8 读取文件,然后将结果转换为整数?抱歉,我是 Python 新手。 关闭文件怎么样?打开文件是一种非常糟糕的做法,使用with
语句可以轻松避免这种做法。答案很有用,但对于像我这样仍在学习如何在 Python 中处理文件的人来说可能会产生误导
@CamelCamelius 请注意,我们可以认为文件会自动关闭,因为句柄超出范围。但情况并非总是如此***.com/questions/2404430/…【参考方案3】:
将二进制文件读入bytes
对象:
from pathlib import Path
data = Path('/path/to/file').read_bytes() # Python 3.5+
从数据的 0-3 字节创建 int
:
i = int.from_bytes(data[:4], byteorder='little', signed=False)
从数据中解包多个int
s:
import struct
ints = struct.unpack('iiii', data[:16])
pathlib
int.from_bytes()
struct
【讨论】:
【参考方案4】:您可以使用numpy.fromfile
,它可以从文本文件和二进制文件中读取数据。您将首先使用numpy.dtype
构造一个表示您的文件格式的数据类型,然后使用numpy.fromfile
从文件中读取此类型。
【讨论】:
很容易错过这个!文档有点薄;请参阅reddit.com/r/Python/comments/19q8nt/… 进行一些讨论【参考方案5】:我也发现 Python 在读写二进制文件方面有欠缺,所以我写了一个小模块(适用于 Python 3.6+)。
使用binaryfile 你会做这样的事情(我猜,因为我不知道 Fortran):
import binaryfile
def particle_file(f):
f.array('group_ids') # Declare group_ids to be an array (so we can use it in a loop)
f.skip(4) # Bytes 1-4
num_particles = f.count('num_particles', 'group_ids', 4) # Bytes 5-8
f.int('num_groups', 4) # Bytes 9-12
f.skip(8) # Bytes 13-20
for i in range(num_particles):
f.struct('group_ids', '>f') # 4 bytes x num_particles
f.skip(4)
with open('myfile.bin', 'rb') as fh:
result = binaryfile.read(fh, particle_file)
print(result)
产生这样的输出:
'group_ids': [(1.0,), (0.0,), (2.0,), (0.0,), (1.0,)],
'__skipped': [b'\x00\x00\x00\x08', b'\x00\x00\x00\x08\x00\x00\x00\x14', b'\x00\x00\x00\x14'],
'num_particles': 5,
'num_groups': 3
我使用 skip() 来跳过 Fortran 添加的其他数据,但您可能希望添加一个实用程序来正确处理 Fortran 记录。如果您这样做,欢迎提出拉取请求。
【讨论】:
【参考方案6】:import pickle
f=open("filename.dat","rb")
try:
while True:
x=pickle.load(f)
print x
except EOFError:
pass
f.close()
【讨论】:
可能值得稍微解释一下为什么这比其他答案更好(或至少与其他答案一样好。 您是否测试过验证这适用于 fortran 生成的二进制文件? 并且还要解释它的作用... 什么是泡菜?pickle.load
加载了什么?它会加载 Fortran 流、直接文件还是顺序文件?它们不同且不兼容。
Pickle 二进制文件包含有关数据的信息。你可以自己测试一下。
你曾经/正在学习 CBSE 计算机科学吗?这对我们的问题和练习来说似乎很熟悉......以上是关于用python读取二进制文件的主要内容,如果未能解决你的问题,请参考以下文章
用python从二进制文件中读取32位带符号的ieee 754浮点?