How to solve 'Fortran runtime error: I/O past end of record on unformatted file'?

How to solve 'Fortran runtime error: I/O past end of record on unformatted file'?

现在我有一个 1024 * 1024 * 1024 的数组,其 dtype 是 float32。首先,我将这个数组以“.bigfile”的格式保存到一个文件中。然后我通过 运行 如下代码将这个大文件转换为 Fort运行 未格式化的文件。

with bigfile.File('filename.bigfile') as bf:
    shape = bf['Field'].attrs['ndarray.shape']
    data = bf['Field'][:].reshape(shape)
    np.asfortranarray(data).tofile('filename.dat')

接下来测试这个二进制文件,即 'filename.dat',我分别按 Python 和 Fort运行95 读取了这个文件。 Python 代码 运行 没问题,代码片段如下所示。

field = np.fromfile('filename.dat', 
                   dtype='float32', count=1024*1024*1024)
density_field = field.reshape(1024, 1024, 1024)

但是,Fortran runtime error发生在我​​运行 Fort运行阅读代码时:

 Program readout00
  Implicit None
  Integer, Parameter :: Ng = 1024
  Real, Allocatable, Dimension(:,:,:) :: dens
  Integer :: istat, ix, iy, iz
  ! -------------------------------------------------------------------------
  ! Allocate the arrays for the original simulation data
  ! -------------------------------------------------------------------------
  Allocate(dens(0:Ng-1, 0:Ng-1, 0:Ng-1), STAT=istat)
  If( istat/=0 ) Stop "Wrong Allocation-1"
  ! -------------------------------------------------------------------------
  Open(10, file="filename.dat", status="old", form="unformatted")
  Read(10) dens
  Close(10)
  Write(*,*) "read-in finished"
  ! -------------------------------------------------------------------------
  Do ix = 0, 1
    Do iy = 0, 1
      Do iz = 0, 1
        Write(*,*) "ix, iy, iz, rho=", ix, iy, iz, dens(ix, iy, iz)
     EndDo
    EndDo
  EndDo
  !--------------------------------------------------------------------------
End Program readout00

错误信息:

At line 13 of file readout00.f90 (unit = 10, file = 'filename.dat')
Fortran runtime error: I/O past end of record on unformatted file



Error termination. Backtrace:
#0  0x7f7d8aff8e3a
#1  0x7f7d8aff9985
#2  0x7f7d8affa13c
#3  0x7f7d8b0c96e0
#4  0x7f7d8b0c59a6
#5  0x400d24
#6  0x400fe1
#7  0x7f7d8a4db730
#8  0x400a58
#9  0xffffffffffffffff

我不明白为什么会出现这些错误。

注意:整体操作在LINUX远程服务器中处理。



经过反复修改read语句,发现Fort运行代码运行没问题 if ix<=632, iy<=632, iz<=632.如果它们大于 632,则会出现 runtime error。我应该如何更正此错误以便 dens 可以读取所有 1024^3 个元素?

Read(10) (((dens(ix, iy, iz), ix=0,632), iy=0,632), iz=0,632)


补充:

今天我在open语句中添加了一个子句acccess=stream,在read(10) dens之前添加了read(10) header,即

Integer :: header
......
Open(10, file="filename.dat", status="old",    &
         form="unformatted", access='stream')
Read(10) header
Read(10) dens

修改后,堡垒运行代码'readout00.f95'读入1024*1024*1024数组,即dens成功

为什么原'readout00.f95'读入dens失败?

@IanH 已在评论中正确回答了您的问题,或者更准确地说是在另一个问题中指出了正确答案。

'unformatted'格式只是表示文件不被解释为human-readable,但文件中的数据需要以特定的方式布局。虽然具体格式不确定,编译器和 system-dependent,但通常每条记录都有自己的 header 和显示数据长度的页脚。

numpy.asfortanarray根本不影响文件布局,它只保证数组在内存中的布局与Fortran相同(Column-Major,或者第一个索引变化最快) ,而不是通常的(Row-Major,或变化最快的最后一个索引)。

看这个例子:

我在 python 和 fortran 中创建了相同的数据(类型 int16,值 0 到 11),并将其存储在两个文件中,python 版本 np.asfortranarray.tofile 和具有未格式化写入的 Fortran。这些是结果:

与Python:

0000000 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0000010 08 00 09 00 0a 00 0b 00

使用 Fortran:

0000000 18 00 00 00 00 00 01 00 02 00 03 00 04 00 05 00
0000010 06 00 07 00 08 00 09 00 0a 00 0b 00 18 00 00 00

在 python 文件中,'data' 立即开始(00 00 表示 0,然后 01 00 表示 1,依此类推,直到 0b 00 for 11),但是在Fortran中,有一个4字节的header:18 00 00 00,也就是24,也就是数据的字节数,然后在最后重复这个值

当您尝试使用 form='unformatted' 使用 Fortran 读取文件时,程序希望找到这种数据,但您拥有的不是这种数据。

解决方案正是您所做的:使用流。在流中,程序期望数据在没有任何 header 或元数据的情况下连续传入。