使用Fortran从文件中提取指定的行

时间:2019-02-16 18:51:48

标签: fortran gfortran fortran90

我正在尝试编写一个从给定文件中提取指定行的函数。我这样做的功能有两个参数:

  1. fUnit:这是给定文件的数字标识符。
  2. fLine:这是我要提取的行号。如果此输入的值为-1,则该函数将返回文件的最后一行(在我的工作中,这是我最需要的功能)。

我已将此功能包装在模块( routines.f95 )中,如下所示:

module routines

contains

function getLine(fUnit, fLine)

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ! Get the nth line of a file. It is assumed that the file is    !
    ! numerical only. The first argument is the unit number of the  !
    ! file, and the second number is the line number. If -1 is      !
    ! passed to the second argument, then the program returns the   !
    ! final line of the program. It is further assumed that each    !
    ! line of the file contains two elements.                       !
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    implicit none

    integer, intent(in) :: fUnit, fLine
    integer :: i
    real, dimension(2) :: tmp, getLine

    if (fline .eq. -1) then
        do
            read(fUnit, *, end=10) tmp
        end do
    else
        do i = 1, fLine
            read(fUnit, *, end=10) tmp
        end do
    end if

10  getLine = tmp

end function getLine

end module routines

要测试此功能,我设置了以下主程序( test.f95 ):

program test

use routines
implicit none

integer :: i
real, dimension(2) :: line

open(21, file = 'data.dat')

do i = 1, 5
    line = getLine(21, i)
    write(*, *) i, line
end do

close(21)
end program test

文件 data.dat 包含以下信息:

1.0 1.00
2.0 0.50
3.0 0.33
4.0 0.25
5.0 0.20

此代码是我编写的代码的简化版本,但是它反映了我在主代码中遇到的所有错误。当我用命令编译上面的代码

gfortran -c routines.f95
gfortran -c test.f95
gfortran -o test test.o routines.o

我没有获得任何语法错误。程序的输出如下:

       1   1.00000000       1.00000000    
       2   3.00000000      0.330000013    
       3   5.00000000      0.200000003    
At line 28 of file routines.f95 (unit = 21, file = 'data.dat')
Fortran runtime error: Sequential READ or WRITE not allowed after EOF marker, possibly use REWIND or BACKSPACE

Error termination. Backtrace:
#0  0x7f2425ea15cd in ???
#1  0x7f2425ea2115 in ???
#2  0x7f2425ea287a in ???
#3  0x7f242601294b in ???
#4  0x400ccb in ???
#5  0x4009f0 in ???
#6  0x400b32 in ???
#7  0x7f2425347f49 in ???
#8  0x400869 in ???
    at ../sysdeps/x86_64/start.S:120
#9  0xffffffffffffffff in ???

我了解到正在引发错误,因为该程序尝试提取超出EOF标记的行。这样做的原因是因为程序跳过了每隔一行,因此跳过了程序的最后一行。

有人可以帮我理解为什么我的程序跳过输入文件的每一行吗?我无法在代码中找到问题。

2 个答案:

答案 0 :(得分:4)

连接的外部文件的位置为 global 状态。在这种情况下,函数getline将在文件搜索后更改其位置。下次调用该函数时,搜索将从其保留的位置开始。

那么,您所看到的并不是行的“跳过”,而是:

  • 在第一次迭代中,读取第一行;
  • 在第二次迭代中,跳过一行(第二条),然后读取一行(第三条);
  • 在第三次迭代中,跳过了两行,并尝试读取第三行。

但是,第三次迭代中的第三行(文件的第六个)在文件结束条件之后。您会看到读取第五行的结果。

要启用所需的查找功能,请确保在跳过行之前将文件放置在其初始位置。 rewind语句将连接文件放置在其初始位置。

代替倒带,您可以关闭文件并用position='rewind'重新打开以确保其位于初始位置,但是rewind语句是一种更好的重定位方法。如果在没有position=指示符的情况下重新打开,则会看到类似于position='asis'的效果。这使Fortran标准未指定文件中的位置。

答案 1 :(得分:2)

在@francescalus的帮助下,我可以回答我自己的问题。我的代码的问题在于,每当我的主程序遍历该函数时,read语句的位置就会在最后一个位置出现。因此,我的程序跳过了几行。这是我更新的代码:

test.f95

program test

use routines

implicit none

integer :: i
real, dimension(2) :: line

open(21, file = 'data.dat')

do i = 1, 5
    line = getLine(21, i)
    write(*, *) i, line
end do

line = getLine(21, -1)
write(*, *) -1, line

close(21)
end program test

routines.f95

module routines

包含

function getLine(fUnit, fLine)

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ! Get the nth line of a file. It is assumed that the file is    !
    ! numerical only. The first argument is the unit number of the  !
    ! file, and the second number is the line number. If -1 is      !
    ! passed to the second argument, then the program returns the   !
    ! final line of the program. It is further assumed that each    !
    ! line of the file contains two elements.                       !
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    implicit none

    integer, intent(in) :: fUnit, fLine
    integer :: i
    real, dimension(2) :: tmp, getLine

    rewind(fUnit)

    if (fline .eq. -1) then
        do
            read(fUnit, *, end=10) tmp
        end do
    else
        do i = 1, fLine
            read(fUnit, *, end=10) tmp
        end do
    end if

10  getLine = tmp

end function getLine

end module routines

data.dat

1.0 1.00
2.0 0.50
3.0 0.33
4.0 0.25
5.0 0.20

编译为

gfortran -c routines.f95
gfortran -c test.f95
gfortran -o test test.o routines.o

该程序的输出为

1   1.00000000       1.00000000    
2   2.00000000      0.500000000    
3   3.00000000      0.330000013    
4   4.00000000      0.250000000    
5   5.00000000      0.200000003    
-1   5.00000000      0.200000003