为了账号安全,请及时绑定邮箱和手机立即绑定

在 Python 中读取直接访问二进制文件格式

在 Python 中读取直接访问二进制文件格式

阿波罗的战车 2021-06-21 17:47:41
背景:使用以下 Fortran 代码在 Linux 机器上读取二进制文件:        parameter(nx=720, ny=360, nday=365)c         dimension tmax(nx,ny,nday),nmax(nx,ny,nday)        dimension tmin(nx,ny,nday),nmin(nx,ny,nday)c         open(10,     &file='FILE',     &access='direct',recl=nx*ny*4)c        do k=1,nday        read(10,rec=(k-1)*4+1)((tmax(i,j,k),i=1,nx),j=1,ny)         read(10,rec=(k-1)*4+2)((nmax(i,j,k),i=1,nx),j=1,ny)         read(10,rec=(k-1)*4+3)((tmin(i,j,k),i=1,nx),j=1,ny)         read(10,rec=(k-1)*4+4)((nmin(i,j,k),i=1,nx),j=1,ny)         end do文件详情:options  little_endiantitle global daily analysis (grid box mean, the grid shown is the center of the grid box)undef -999.0xdef 720 linear    0.25 0.50ydef 360  linear -89.75 0.50zdef 1 linear 1 1tdef 365 linear 01jan2015 1dyvars 4tmax     1  00 daily maximum temperature (C)nmax     1  00 number of reports for maximum temperature (C)tmin     1  00 daily minimum temperature (C)nmin     1  00 number of reports for minimum temperature (C)ENDVARS尝试解决方案:我正在尝试使用以下代码(故意省略两个属性)将其解析为 python 中的数组:with gzip.open("/FILE.gz", "rb") as infile:     data = numpy.frombuffer(infile.read(), dtype=numpy.dtype('<f4'), count = -1)while x <= len(data) / 4:    tmax.append(data[(x-1)*4])    tmin.append(data[(x-1)*4 + 2])    x += 1data_full = zip(tmax, tmin)在测试某些记录时,使用 Fortran 时,数据似乎与文件中的某些示例记录不一致。我也尝试dtype=numpy.float32过,但没有成功。就观察次数而言,似乎我正在正确读取文件。struct在我知道文件是用 Fortran 创建的之前,我也在使用。那不起作用这里有类似的问题,其中一些问题的答案我已经尝试适应但没有运气。
查看完整描述

2 回答

?
紫衣仙女

TA贡献1839条经验 获得超15个赞

在我的问题中更新之后,我意识到我的循环方式有误。我当然在发出赏金后大约 10 分钟发现了这一点,好吧。


错误在于使用一天来遍历记录。这将不起作用,因为它每个循环迭代一次,没有将记录推得足够远。因此,为什么有些分钟高于最大值。新代码是:


while nday < 365:

    tmax = numpy.append(tmax, data[(nx*ny)*rm:(nx*ny)*(rm + 1)].reshape((nx,ny), order='F'))

    rm = rm + 2

    tmin = numpy.append(tmin, data[(nx*ny)*rm:(nx*ny)*(rm + 1)].reshape((nx,ny), order='F'))

    rm = rm + 2

    nday += 1 

这使用了记录移动器(或rm我称之为)来移动记录适当的数量。这就是它所需要的。


查看完整回答
反对 回复 2021-06-29
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

虽然 Fortran 二进制文件的确切格式取决于编译器,但在所有情况下,我都知道直接访问文件(access='direct'如本问题中那样打开的文件)在记录之间没有任何记录标记。每条记录的大小都是固定的,由语句recl=中的OPEN说明符给出。也就是说,记录N(N - 1) * RECL文件中的偏移字节开始。

一个可移植性问题是 的单位recl=file storage units。对于大多数编译器,file storage unit以 8 位八位字节指定大小(如 Fortran 标准的最新版本所推荐),但对于英特尔 Fortran 编译器,recl=以 32 位为单位;有一个命令行选项-assume byterecl可用于使英特尔 Fortran 与大多数其他编译器相匹配。

因此,在此处给出的示例中,假设为 8 位file storage unit,则您的 recl 将为 1036800 字节。

此外,查看代码,似乎假设数组是 4 字节类型(例如整数或单精度实数)。因此,如果它是单精度实数,并且文件是以小端创建的,那么<f4您使用的 numpy dtype似乎是正确的选择。

现在,回到英特尔 Fortran 编译器的问题上,如果文件是由 ifort 创建的,-assume byterecl那么您想要的数据将位于每条记录的第一季度,其余部分是填充(全为零或什至随机数据?) . 然后你必须做一些额外的体操来提取python中的正确数据而不是填充。通过检查文件的大小,是它nx * ny * 4 * nday *4还是nx * ny * 4 * nday * 4 * 4字节,应该很容易检查这一点?


查看完整回答
反对 回复 2021-06-29
  • 2 回答
  • 0 关注
  • 203 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信