提问人:Mateus da Silva Teixeira 提问时间:3/2/2018 最后编辑:CommunityMateus da Silva Teixeira 更新时间:3/6/2018 访问量:1001
Fortran 正在读取超出结束文件记录的范围
Fortran is reading beyond endfile record
问:
我正在尝试从文件中读取一些数据,而结束文件记录检测对于停止读取很重要。但是,根据用于读取数据的数组的数组维度,我无法正确检测结束文件记录,并且我的 Fortran 程序停止。
程序如下:
!integer, dimension(3) :: x ! line 1.1
!integer, dimension(3,10) :: x ! line 1.2
integer, dimension(10,3) :: ! line 1.3
integer :: status,i=1
character(len=100) :: error
open( 30, file='data.dat', status='old' )
do
print *,i
!read( 30, *, iostat=status, iomsg=error ) x ! line 2.1
!read( 30, *, iostat=status, iomsg=error ) x(:,i) ! line 2.2
read( 30, *, iostat=status, iomsg=error ) x(i,:) ! line 2.3
if ( status < 0 ) then print *,'EOF'
print *,'total of ',i-1,' lines read.'
exit
else if ( status > 0 ) then
print *,'error cod: ',status
print *,'error message: ', error
stop
else if ( status == 0 ) then
print *,'reading ok.'
i = i + 1
end if
end do
使用“data.dat”文件:
10 20 30
30 40 50
当第 1.3 行和第 2.3 行未注释时,会出现上述错误:
错误编码:5008
错误消息:读取过去的 ENDFILE 记录
但是,使用第 1.1 行和第 2.1 行,或第 1.2 行和第 2.2 行,程序可以工作,检测结束文件记录。
因此,我希望得到一些帮助,以理解为什么我不能使用第 1.3 行和第 2.3 行来正确读取此文件,因为我为读取命令提供了正确数量的数组元素。
我正在使用 gfortran 编译器,版本 6.3.0。
编辑:更简单的例子
以下生成 5008“Read past ENDFILE record”错误:
implicit none
integer x(2,2),s
open(20,file='noexist')
read(20,*,iostat=s)x
write(*,*)s
end
如果我们制作一个标量或一维数组(任何大小),我们会得到预期的EOF标志。文件实际上不存在或为空并不重要。如果文件包含一些但不够的数据,则很难理解您可能获得的返回值。x
-1
答:
我不确定我是否正确地表达了自己,但这与 fortran 读取和存储 2d 数组的方式有关。当您使用此表示法时: ,列实际上是内联展开的,并且使用这一行代码读取项目。在使用的其他情况下,该行的读取方式就像您多次调用一样。
如果您想坚持使用特定的形状和大小,您可以使用隐含循环。例如,您可以使用类似这样的东西:x(:,i)
i
x(i,:)
i
read
read( 30, *, iostat=status, iomsg=error ) (x(i,j), j=1,3)
在任何情况下,您都应该检查您的数据是否正确存储在变量中(至少符合预期)。x
评论
(x(i,j),j=1,3)
x(i,1:3)
x(i,:)
请注意,这只是一个猜测。请记住,Fortran 按列主要顺序存储数组。当 gfortran 编译时,3 个内存位置彼此相邻,因此在可执行文件中,它会生成对操作系统的单个调用,以从文件中读取 3 个值。read() x(:,i)
现在编译时,三个数据元素 和 不在连续的内存中。所以我猜测可执行文件实际上对操作系统有 3 次读取调用。第一个会捕获 EOF,但第二个会给你 read past end of file 错误。read() x(i,:)
x(i,1)
x(i,2)
x(i,3)
更新:我已经确认英特尔的 ifort 不会发生这种情况。gfortran 之前似乎也遇到过类似的问题:读取 NAMELIST 超过 EOF 时 IOSTAT 值错误。这是否是一个错误是值得商榷的。该代码看起来确实应该捕获 EOF。
评论
status < 0 .or. status == 5008