【问题标题】:Reading a binary file with python用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 函数可以轻松读取二进制文件。我推荐它。
  • ...并始终注意您的字节序,尤其是。在不同制造商的计算机之间移植时。

标签: python binary fortran


【解决方案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:])

【讨论】:

  • 你能看看这个其他帖子吗? stackoverflow.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 请注意,我们可以认为文件会自动关闭,因为句柄超出范围。但情况并非总是如此stackoverflow.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])

【讨论】:

    【解决方案4】:

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

    【讨论】:

    【解决方案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 计算机科学吗?这对我们的问题和练习来说似乎很熟悉......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 2011-12-26
      • 2021-03-29
      • 1970-01-01
      相关资源
      最近更新 更多