用python读取二进制文件


104

我发现用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程序,读取此二进制文件,然后保存需要使用的数据?


1
该文件是由Fortran程序编写的吗?如果是这样,它是如何写入的,因为默认情况下,Fortran会在将每个记录写入文件之前添加其他数据。在读取数据时,您可能需要注意这一点。
克里斯

1
请忽略我之前的评论,整数8和4 * N显然是此附加数据。
克里斯

2
另外,请参阅python中读取二进制文件的问题的答案。
克里斯

Numpy的fromfile功能使读取二进制文件变得容易。我推荐它。
littleO

...并且要特别注意您的字节序,尤其是 在不同制造商的计算机之间移植时。
DragonLord

Answers:


154

读取二进制文件内容,如下所示:

with open(fileName, mode='rb') as file: # b is important -> binary
    fileContent = file.read()

然后使用struct.unpack “解压缩”二进制数据:

起始字节: struct.unpack("iiiii", fileContent[:20])

正文:忽略标题字节和尾随字节(= 24);其余部分构成主体,要知道主体中的字节数除以4,就可以得到整数。将获得的商乘以字符串'i'以为unpack方法创建正确的格式:

struct.unpack("i" * ((len(fileContent) -24) // 4), fileContent[20:-4])

结束字节: struct.unpack("i", fileContent[-4:])


你能看看这个帖子吗?stackoverflow.com/questions/8092469/… ...我还是要读取另一个二进制文件,但是在这种情况下,我不知道字节结构的详细信息。例如,我发现有时存在整数8。但是,使用IDL,读取此数据确实非常简单。我可以用python做同样的事情吗?
布赖恩2012年

请指出(在其他帖子内,不在此处)为什么您对发布的答案和评论不满意。也许您还应该更新该问题以提供更多详细信息...更新后我将对其进行介绍。
gecco,2012年

如果您需要将解压后的char []转换为字符串,请参见此答案。
PeterM

import struct
JW

23

通常,我建议您考虑使用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新手。
布赖恩


11

要将二进制文件读取到bytes对象:

from pathlib import Path
data = Path('/path/to/file').read_bytes()  # Python 3.5+

要从int字节0-3 创建数据:

i = int.from_bytes(data[:4], byteorder='little', signed=False)

要从int数据中解压缩多个:

import struct
ints = struct.unpack('iiii', data[:16])

0

我也发现在读取和写入二进制文件方面缺少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记录。如果您这样做,将欢迎提出请求。


-2
import pickle
f=open("filename.dat","rb")
try:
    while True:
        x=pickle.load(f)
        print x
except EOFError:
    pass
f.close()

6
大概值得解释一下为什么它比其他答案更好(或至少与其他答案一样好)。
菲尔(Phil)

2
您是否测试了经过验证的功能,可以与fortran生成的二进制文件一起使用?
agentp

1
并解释一下它的作用。什么是泡菜?什么pickle.load负荷?是否加载Fortran流,直接文件或顺序文件?它们是不同的并且不兼容。
弗拉基米尔F
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.