Fortran 正在读取超出结束文件记录的范围

Fortran is reading beyond endfile record

提问人:Mateus da Silva Teixeira 提问时间:3/2/2018 最后编辑:CommunityMateus da Silva Teixeira 更新时间:3/6/2018 访问量:1001

问:

我正在尝试从文件中读取一些数据,而结束文件记录检测对于停止读取很重要。但是,根据用于读取数据的数组的数组维度,我无法正确检测结束文件记录,并且我的 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 GFORTRAN EOF 数据文件

评论

1赞 francescalus 3/3/2018
请显示运行此程序时的输出(工作和非工作变体)。我不清楚为什么您会收到有关文件结束条件的消息,因此确切的输出将澄清。
0赞 Ross 3/3/2018
第 1.3 行中没有“x”。这只是一个转录错误吗?
0赞 Ross 3/3/2018
有趣。我能够用 gfortran 4.8 复制这个问题,但不能复制 ifort 16.0。我同意这是一个问题。
0赞 Ross 3/3/2018
GFORTRAN 7.2 也有同样的问题。
0赞 agentp 3/3/2018
已确认,(GFORTRAN 4.8.5)。我编辑了问题以显示我收到的实际消息。这显然是一个 Gfortran 错误。只需进行第一次测试即可解决status < 0 .or. status == 5008

答:

-1赞 Aristotelis 3/2/2018 #1

我不确定我是否正确地表达了自己,但这与 fortran 读取和存储 2d 数组的方式有关。当您使用此表示法时: ,列实际上是内联展开的,并且使用这一行代码读取项目。在使用的其他情况下,该行的读取方式就像您多次调用一样。 如果您想坚持使用特定的形状和大小,您可以使用隐含循环。例如,您可以使用类似这样的东西:x(:,i)ix(i,:)ireadread( 30, *, iostat=status, iomsg=error ) (x(i,j), j=1,3)

在任何情况下,您都应该检查您的数据是否正确存储在变量中(至少符合预期)。x

评论

1赞 francescalus 3/3/2018
为什么你期望与?为什么使用就像使用多个 read 语句一样?(x(i,j),j=1,3)x(i,1:3)x(i,:)
0赞 Ross 3/3/2018
我不认为这回答了这个问题。
0赞 Aristotelis 3/3/2018
@francescalus 我同意它不应该有所不同,但它以前发生在我身上。一些编译器表现出我所描述的行为。
-1赞 Dan Sp. 3/3/2018 #2

请注意,这只是一个猜测。请记住,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。

评论

0赞 Ross 3/3/2018
我不认为这回答了这个问题。
1赞 Vladimir F Героям слава 3/6/2018
名称列表输入与普通文件输入有很大不同。