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

使用Fortran从文件中提取指定行,fortran,gfortran,fortran90,Fortran,Gfortran,Fortran90,我试图编写一个函数,从给定的文件中提取指定的行。我的函数有两个参数: fUnit:这是给定文件的数字标识符 弗林:这是我想提取的行号。如果此输入的值为-1,则函数将返回文件的最后一行(在我的工作中,这是我最需要的功能) 我将此函数包装在一个模块(routines.f95)中,如图所示: module routines contains function getLine(fUnit, fLine) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

我试图编写一个函数,从给定的文件中提取指定的行。我的函数有两个参数:

  • fUnit:这是给定文件的数字标识符
  • 弗林:这是我想提取的行号。如果此输入的值为-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):

    文件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标记的线。这是因为程序每隔一行跳过一行,从而跳过程序中的最后一行


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

    在@francescalus的帮助下,我可以回答我自己的问题。我的代码的问题是,每次我的主程序迭代函数时,read语句的位置都在最后一个位置。因此,我的程序跳过了行。这是我的更新代码:

    测试.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
    
    module routines
    
    例行程序。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
    
    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
    
    数据.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 
    

    连接的外部文件的位置是全局状态。在这种情况下,函数
    getline
    会在搜索后更改文件的位置。下次调用该函数时,搜索将从它离开的位置开始

    因此,您看到的不是太多的“跳过”行,而是:

    • 在第一次迭代中,读取第一行
    • 在第二次迭代中,跳过一行(第二行),然后读取一行(第三行)
    • 在第三次迭代中,跳过两行,并尝试读取第三行
    但是,第三次迭代中的第三行(文件的第六行)在文件结束条件之后。您可以看到阅读第五行的结果

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


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

    您是否缺少了一个
    倒带
    ?我认为倒带会将我的read语句移回文件的开头,这不是我想要的。我希望我的代码逐行遍历文件的行,直到找到它需要的行。但是在您第一次调用
    getLine
    后,文件仍位于该行之后。下次打电话时,你不是在找第二行,而是在找第一行之后的两行。所以,您希望在调用
    getLine
    之间进行回放。好的,我想我明白您的意思了。在调用之间,read语句的位置不会刷新到文件的开头,我认为它会刷新到文件的开头。我将尝试在函数的开头添加一个rewind语句,看看是否有效。非常感谢你!非常感谢你的帮助。你的建议非常有效。如果你不介意的话,我还有一个后续问题。如果在再次迭代之前关闭文件并重新打开它,这会自动重置read语句的位置吗?我怀疑这是因为文件被重新加载到程序内存中。