【问题标题】:Fortran is reading beyond endfile recordFortran 正在读取超出 endfile 记录的内容
【发布时间】:2018-08-10 18:09:15
【问题描述】:

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

所以,我想帮助我理解为什么我不能使用第 1.3 行和第 2.3 行来正确读取这个文件,因为我为读取命令提供了正确数量的数组元素。

我正在使用 gfortran 编译器,版本 6.3.0。

编辑:更简单的例子

以下会产生 5008“读取过去的 ENDFILE 记录”错误:

implicit none
integer x(2,2),s
open(20,file='noexist')
read(20,*,iostat=s)x
write(*,*)s
end

如果我们将x 设为标量或一维数组(任意大小),我们将得到预期的-1 EOF 标志。文件实际上不存在或为空都没有关系。如果文件包含一些,但还不够,则数据很难理解您可能会得到哪个返回值。

【问题讨论】:

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

标签: fortran gfortran eof data-files


【解决方案1】:

我不确定我是否正确地表达了自己,但这与 fortran 读取和存储二维数组的方式有关。当您使用此表示法时: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,:) 就像使用多个读取语句一样?
  • 我认为这不能回答问题。
  • @francescalus 我同意它不应该有所不同,但它以前发生在我身上。一些编译器表现出我所描述的行为。
【解决方案2】:

请注意,这只是一个猜测。请记住,Fortran 按列主要顺序存储数组。当 gfortran 编译 read() x(:,i) 时,这 3 个内存位置彼此相邻,因此在可执行文件中,它会产生对操作系统的一次调用以从文件中读取 3 个值。

现在当read() x(i,:)被编译时,x(i,1)x(i,2)x(i,3)这三个数据元素不在连续内存中。所以我猜测可执行文件实际上对操作系统有 3 次读取调用。第一个会捕获 EOF,但第二个会为您提供文件读取结束错误。

更新:我已经确认英特尔的 ifort 不会发生这种情况。 gfortran 之前似乎也遇到过类似的问题:Bad IOSTAT values when readings NAMELISTs past EOF。这是否是一个错误是有争议的。该代码当然看起来应该捕获 EOF。

【讨论】:

  • 我认为这不能回答问题。
  • 名单输入与普通文件输入有很大不同。
猜你喜欢
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
相关资源
最近更新 更多