Fortran ftell 返回错误位置
Fortran ftell returning to wrong position
这是一段简单的代码,它从文件中读取行,然后 returns 到上一个位置并重新读取同一行:
program main
implicit none
integer :: unit, pos, stat
character(128) :: buffer
! Open file as formatted stream
open( NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", STATUS="old", ACTION="read", IOSTAT=stat )
if ( stat /= 0 ) error stop
! Skip 2 lines
read (unit,*) buffer
read (unit,*) buffer
! Store position
pos = ftell(unit)
! Read & write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Return to previous position
call fseek(unit,pos,0)
! pos = ftell(unit) ! <-- ?!
! Read & write next line (should be same output)
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Close file stream
close (UNIT=unit)
end program main
“data.txt”只是一个包含 4 行的虚拟文件:
1
2
3
4
现在,当我编译代码片段 (gfortran 9.3.0) 并 运行 它时,我得到了一个答案:
buffer=3
buffer=4
这是错误的,因为它们应该是一样的。更有趣的是,当我在 'fseek' 之后添加一个额外的 ftell
(代码段中的注释行)时,我得到了正确答案:
buffer=3
buffer=3
知道为什么会这样吗?还是我使用 ftell
和 fseek
不正确?
gfortran 的 FTELL
和 FSEEK
文档明确指出提供这些例程是为了向后兼容 g77。由于您的代码使用 NEWUNIT
、ERROR STOP
和 STREAM
访问权限,因此您没有编译旧的发霉代码。您应该使用@Vladimir 指出的符合标准的方法。
快速调试会话显示 FTELL
和 FSEEK
对文件位置使用基于 0 的引用,而现代 Fortran 的 inquire
方法是基于 1 的。 gfortran 中可能存在一个 off-by-one 类型错误,但由于 FTELL
和 FSEEK
是为了向后兼容 g77(一个未维护的 15 岁以上编译器),有人需要做一些代码探索以确定预期的行为。我怀疑 none 当前活跃的 gfortran 开发人员足够关心探索这个问题。所以,解决你的问题
program main
implicit none
integer pos, stat, unit
character(128) buffer
! Open file as formatted stream
open(NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", &
& STATUS="old", ACTION="read", IOSTAT=stat)
if (stat /= 0) stop
! Skip 2 lines
read (unit,*) buffer
read (unit,*) buffer
! Store position
inquire(unit, pos=pos)
! Read & write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Reread & write line (should be same output)
read (unit,*,pos=pos) buffer
write (*,*) "buffer=", trim(buffer)
! Close file stream
close (UNIT=unit)
end program main
这是一段简单的代码,它从文件中读取行,然后 returns 到上一个位置并重新读取同一行:
program main
implicit none
integer :: unit, pos, stat
character(128) :: buffer
! Open file as formatted stream
open( NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", STATUS="old", ACTION="read", IOSTAT=stat )
if ( stat /= 0 ) error stop
! Skip 2 lines
read (unit,*) buffer
read (unit,*) buffer
! Store position
pos = ftell(unit)
! Read & write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Return to previous position
call fseek(unit,pos,0)
! pos = ftell(unit) ! <-- ?!
! Read & write next line (should be same output)
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Close file stream
close (UNIT=unit)
end program main
“data.txt”只是一个包含 4 行的虚拟文件:
1
2
3
4
现在,当我编译代码片段 (gfortran 9.3.0) 并 运行 它时,我得到了一个答案:
buffer=3
buffer=4
这是错误的,因为它们应该是一样的。更有趣的是,当我在 'fseek' 之后添加一个额外的 ftell
(代码段中的注释行)时,我得到了正确答案:
buffer=3
buffer=3
知道为什么会这样吗?还是我使用 ftell
和 fseek
不正确?
gfortran 的 FTELL
和 FSEEK
文档明确指出提供这些例程是为了向后兼容 g77。由于您的代码使用 NEWUNIT
、ERROR STOP
和 STREAM
访问权限,因此您没有编译旧的发霉代码。您应该使用@Vladimir 指出的符合标准的方法。
快速调试会话显示 FTELL
和 FSEEK
对文件位置使用基于 0 的引用,而现代 Fortran 的 inquire
方法是基于 1 的。 gfortran 中可能存在一个 off-by-one 类型错误,但由于 FTELL
和 FSEEK
是为了向后兼容 g77(一个未维护的 15 岁以上编译器),有人需要做一些代码探索以确定预期的行为。我怀疑 none 当前活跃的 gfortran 开发人员足够关心探索这个问题。所以,解决你的问题
program main
implicit none
integer pos, stat, unit
character(128) buffer
! Open file as formatted stream
open(NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", &
& STATUS="old", ACTION="read", IOSTAT=stat)
if (stat /= 0) stop
! Skip 2 lines
read (unit,*) buffer
read (unit,*) buffer
! Store position
inquire(unit, pos=pos)
! Read & write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Reread & write line (should be same output)
read (unit,*,pos=pos) buffer
write (*,*) "buffer=", trim(buffer)
! Close file stream
close (UNIT=unit)
end program main