我在 Python 中读取未格式化的 F77 二进制文件时遇到问题。
我试过 SciPy.io.FortraFile
方法和 NumPy.fromfile
方法,都无济于事。我还阅读了 IDL 中的文件,该文件有效,因此我有一个关于数据应该是什么样子的基准。我希望有人能指出我的一个愚蠢的错误——没有什么比度过一个白痴时刻然后洗手更好的了……
数据 bcube1 的尺寸为 101x101x101x3,并且是 r*8 类型。共有 3090903 个条目。它们是使用以下语句编写的(不是我的代码,从源代码复制)。
open (unit=21, file=bendnm, status='new'
. ,form='unformatted')
write (21) bcube1
close (unit=21)
我可以使用以下内容在 IDL 中成功读取它(也不是我的代码,从同事那里复制的):
bcube=dblarr(101,101,101,3)
openr,lun,'bcube.0000000',/get_lun,/f77_unformatted,/swap_if_little_endian
readu,lun,bcube
free_lun,lun
返回的数据 (bcube) 是 double 的,尺寸为 101x101x101x3,因此文件的标题信息知道其尺寸(不是扁平化)。
现在我尝试使用 Python 获得相同的效果,但没有运气。我尝试了以下方法。
In [30]: f = scipy.io.FortranFile('bcube.0000000', header_dtype='uint32')
In [31]: b = f.read_record(dtype='float64')
返回错误
Size obtained (3092150529) is not a multiple of the dtypes given (8)
.更改 dtype 会更改获得的大小,但它仍然不能被 8 整除。或者,使用
fromfile
结果没有错误,但返回数组中的另一个值(也许是页脚?),并且单个数组值非常错误(都应该是统一的)。In [38]: f = np.fromfile('bcube.0000000')
In [39]: f.shape
Out[39]: (3090904,)
In [42]: f
Out[42]: array([ -3.09179121e-030, 4.97284231e-020, -1.06514594e+299, ...,
8.97359707e-029, 6.79921640e-316, -1.79102266e-037])
我试过使用 byteswap 来查看这是否使浮点值更合理,但事实并非如此。
在我看来,
np.fromfile
方法非常接近工作,但它读取标题信息的方式一定有问题。任何人都可以建议我如何找出头文件中允许 IDL 了解数组维度和数据类型的内容吗?有没有办法将标题信息传递给 fromfile
以便它知道如何对待领先的条目?
最佳答案
我玩了一下,我想我有一个想法。
Fortran 存储未格式化数据的方式没有标准化,因此您必须尝试一下,但您需要三条信息:
头部通常以字节为单位存储记录的长度,并在末尾重复。
再说一次,它不是标准化的,所以没有保证。
从技术上讲,对于标题和值,但我认为它们是相同的。
Python 默认为 little endian,所以如果这是您数据的正确设置,我想您已经解决了。
当您使用
scipy.io.FortranFile
打开文件时,你需要给出头部的数据类型。因此,如果数据存储为 big_endian,并且您有一个 4 字节的无符号整数 header ,则您需要:from scipy.io import FortranFile
ff = FortranFile('data.dat', 'r', '>u4')
读取数据时,需要值的数据类型。同样,假设 big_endian,您需要输入
>f8
:vals = ff.read_reals('>f8')
看 here用于数据类型语法的描述。
如果您可以控制写入数据的程序,我强烈建议您将它们写入数据流中,这样 Python 更容易读取。
关于numpy - 用 Python 读取 Fortran 二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53639058/