用 python 读取二进制文件

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

407508 次浏览

一般来说,我建议您考虑使用 Python 的 结构模块来实现这一点。它是 Python 的标准,并且应该很容易将问题的规范转换为适合于 struct.unpack()的格式化字符串。

请注意,如果在字段之间/周围有“不可见”的填充,那么您需要计算出来并将其包含在 unpack()调用中,否则您将读取错误的位。

读取文件内容以便解压缩某些内容非常简单:

import struct


data = open("from_fortran.bin", "rb").read()


(eight, N) = struct.unpack("@II", data)

这将解压前两个字段,假设它们从文件的最开始开始(没有填充或无关数据) ,并假设它们是本机字节顺序(@符号)。格式化字符串中的 I表示“无符号整数,32位”。

您可以使用 numpy.fromfile,它可以从文本文件和二进制文件中读取数据。首先使用 numpy.dtype构造一个表示文件格式的数据类型,然后使用 numpy.fromfile从文件中读取该类型。

阅读二进制文件内容如下:

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:])

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

将二进制文件读入 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:

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

我也发现 Python 在读写二进制文件方面存在缺陷,所以我编写了一个小模块(针对 Python 3.6 +)。

对于 二进制文件,你可以这样做(我猜,因为我不知道 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 记录。如果您这样做,欢迎您提出请求。

#!/usr/bin/python


import array
data = array.array('f')
f = open('c:\\code\\c_code\\no1.dat', 'rb')
data.fromfile(f, 5)
print(data)