使用 Fortran 从文件中提取指定行
Extract Specified Line from File Using Fortran
我正在尝试编写一个从给定文件中提取指定行的函数。我这样做的函数有两个参数:
- fUnit:这是给定文件的数字标识符。
- fLine:这是我要提取的行号。如果此输入的值为 -1,则该函数将 return 文件的最后一行(在我的工作中,这是我最需要的功能)。
我已经将这个函数封装在一个模块中(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 标记的行。这是因为程序每隔一行就跳过一次,因此跳过了程序中的最后一行。
有人可以帮我理解为什么我的程序会跳过输入文件的每一行吗?我无法在我的代码中找到问题。
在@francescalus 的帮助下,我可以回答我自己的问题了。我的代码的问题是,每次我的主程序迭代函数时,读取语句的位置都是在最后一个位置拾取的。因此,我的程序跳行了。这是我更新的代码:
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
连接的外部文件的位置是全局状态。在这种情况下,函数 getline
在搜索后更改文件的位置。下次调用该函数时,将从它离开的位置开始搜索。
那么,您看到的不是 "skipping" 行,而是:
- 在第一次迭代中,读取第一行;
- 在第二次迭代中,跳过一行(第二行),然后读取一行(第三行);
- 在第三次迭代中,跳过两行并尝试读取第三行。
但是,第三次迭代中的第三行(文件的 第六行 )在文件结束条件之后。你看到读取第五行的结果。
要根据需要启用搜索,请确保在跳过行之前将文件定位在其初始点。 rewind
语句将连接的文件放在其初始位置。
您可以关闭文件并使用 position='rewind'
重新打开以确保它位于初始点,而不是倒带,但 rewind
语句是重新定位的更好方法。如果您在没有 position=
说明符的情况下重新打开,您会看到类似于 position='asis'
的效果。这使得文件中的位置未按 Fortran 标准指定。
我正在尝试编写一个从给定文件中提取指定行的函数。我这样做的函数有两个参数:
- fUnit:这是给定文件的数字标识符。
- fLine:这是我要提取的行号。如果此输入的值为 -1,则该函数将 return 文件的最后一行(在我的工作中,这是我最需要的功能)。
我已经将这个函数封装在一个模块中(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 标记的行。这是因为程序每隔一行就跳过一次,因此跳过了程序中的最后一行。
有人可以帮我理解为什么我的程序会跳过输入文件的每一行吗?我无法在我的代码中找到问题。
在@francescalus 的帮助下,我可以回答我自己的问题了。我的代码的问题是,每次我的主程序迭代函数时,读取语句的位置都是在最后一个位置拾取的。因此,我的程序跳行了。这是我更新的代码:
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
连接的外部文件的位置是全局状态。在这种情况下,函数 getline
在搜索后更改文件的位置。下次调用该函数时,将从它离开的位置开始搜索。
那么,您看到的不是 "skipping" 行,而是:
- 在第一次迭代中,读取第一行;
- 在第二次迭代中,跳过一行(第二行),然后读取一行(第三行);
- 在第三次迭代中,跳过两行并尝试读取第三行。
但是,第三次迭代中的第三行(文件的 第六行 )在文件结束条件之后。你看到读取第五行的结果。
要根据需要启用搜索,请确保在跳过行之前将文件定位在其初始点。 rewind
语句将连接的文件放在其初始位置。
您可以关闭文件并使用 position='rewind'
重新打开以确保它位于初始点,而不是倒带,但 rewind
语句是重新定位的更好方法。如果您在没有 position=
说明符的情况下重新打开,您会看到类似于 position='asis'
的效果。这使得文件中的位置未按 Fortran 标准指定。