python - 如何解决“Fortran 运行时错误:未格式化文件上的 I/O 超过记录结尾”?
问题描述
现在我有一个 1024 * 1024 * 1024 数组,其 dtype 是float32
. 首先,我将此数组以“.bigfile”的格式保存到一个文件中。然后我通过运行如下代码将此大文件转换为 Fortran 无格式文件。
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 和 Fortran95 读取了这个文件。Python 代码运行良好,代码片段如下所示。
field = np.fromfile('filename.dat',
dtype='float32', count=1024*1024*1024)
density_field = field.reshape(1024, 1024, 1024)
但是,Fortran runtime error
当我运行 Fortran 阅读代码时发生:
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
语句后,发现 Fortran 代码运行良好 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)
补充:
今天我acccess=stream
在open
语句中添加了一个子句,在,read(10) header
之前read(10) dens
Integer :: header
......
Open(10, file="filename.dat", status="old", &
form="unformatted", access='stream')
Read(10) header
Read(10) dens
修改后Fortran代码readout00.f95读入1024*1024*1024数组,即dens
成功。
为什么原始的“readout00.f95”无法读入dens
?
解决方案
@IanH 在评论中正确回答了您的问题,或者更准确地说,在另一个问题中指出了正确答案。
“未格式化”格式只是意味着文件不被解释为人类可读,但文件中的数据需要以特定方式布局。虽然具体格式不确定,并且取决于编译器和系统,但通常每条记录都有自己的页眉和页脚,用于显示数据的长度。
根本不影响文件布局,numpy.asfortanarray
它只确保内存中数组的布局与 Fortran 相同(Column-Major,或第一个索引变化最快),而不是通常的(Row-Major,或最后一个索引变化最快)。
看这个例子:
我在 python 和 fortran 中创建了相同的数据(类型 int16,值 0 到 11),并将其存储在两个文件中,np.asfortranarray.tofile
带有未格式化写入的 python 版本和 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 文件中,“数据”立即开始(00 00
对于 0,然后01 00
对于 1,依此类推,直到0b 00
对于 11),但在 Fortran 中,有一个 4 字节的标头:18 00 00 00
,或 24,它是字节数数据,然后在最后重复该值。
当您尝试使用 Fortran 读取文件时form='unformatted'
,这是程序期望找到的数据类型,但这不是您拥有的数据。
解决方案正是您所做的:使用流。在流中,程序期望数据连续进入,没有任何标题或元数据。
推荐阅读
- java - 如何解决此错误:在模块中发现重复的类 com.google.android.gms.internal.vision.zzw
- javascript - 使用 swiperjs api 单击后如何等待 1 秒以移动另一个滑块?
- r - 对所有列应用乘法,但仅适用于具有正值的行
- javascript - TSX:数字输入的道具类型定义
- c# - 如何使用firesharp c#库(未知的确切子路径)从firebase检索数据?
- java - Google 驱动器 API 出现 500 内部服务器错误
- python - 处理日期时间
- javafx - 根据单击的按钮将选项卡添加到 TabPane
- c# - 需要在 Xamarin 中的条目中输入值
- angular - Angular 8 本机选择在更改事件上返回 [object object]