用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)

这将解包前两个字段,假设它们从文件的最开头开始(没有填充或无关数据),并且还假设本机字节顺序(@ 符号)。格式化字符串中的Is 表示“无符号整数,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)

从数据中解包多个ints:

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读取二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

用C++写的二进制文件,用JAVA怎么读取?

用python从二进制文件中读取32位带符号的ieee 754浮点?

用C++写的二进制文件,用JAVA怎么读取?

Python中读取二进制图片(例如 a.jpg)有关解码编码的问题

python读取文件操作文件放在哪里

python读取C#写的二进制文件,byte类型unpack