#fortran
#fortran
Вопрос:
Вот фрагмент простого кода, который считывает строку из файла, затем возвращается в предыдущую позицию и перечитывает ту же строку:
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 amp; write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Return to previous position
call fseek(unit,pos,0)
! pos = ftell(unit) ! <-- ?!
! Read amp; 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
что неверно, поскольку они должны быть одинаковыми. Что еще интереснее, когда я добавляю дополнительную ftell
(прокомментированную строку во фрагменте) после ‘fseek’, я получаю правильный ответ:
buffer=3
buffer=3
Есть идеи, почему он это делает? или я использую ftell
и fseek
неправильно?
Комментарии:
1. Обратите внимание, что ftell и fseek являются устаревшими нестандартными расширениями компилятора, которые не будут работать во всех компиляторах и не должны использоваться в новом коде. Если вы используете
access="stream"
, вы должны использоватьinquire
иread(unit,pos=)
.2. Второй @VladimirF, который опередил меня на секунду — посмотрите на запрос ( …. pos = … ) и напишите ( … pos = … ) для стандартного способа сделать это
Ответ №1:
в документации gfortran для FTELL
и FSEEK
четко указано, что эти процедуры предусмотрены для обратной совместимости с g77. Поскольку ваш код использует NEWUNIT
, ERROR STOP
, и STREAM
access , вы не компилируете старый заплесневелый код. Вы должны использовать стандартные методы, соответствующие требованиям, как указано @Vladimir.
Быстрый сеанс отладки показывает это FTELL
и FSEEK
использует ссылку на 0 для позиции файла, в то время inquire
как метод современного Fortran основан на 1. В gfortran может быть ошибка типа off-by-one, но, как FTELL
и FSEEK
для обратной совместимости с g77 (не поддерживаемый компилятор 15 летней давности), кому-то потребуется выполнить некоторую проверку кода, чтобы определить предполагаемое поведение. Я подозреваю, что ни один из нынешних активных разработчиков 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", amp;
amp; 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 amp; write next line
read (unit,*) buffer
write (*,*) "buffer=", trim(buffer)
! Reread amp; write line (should be same output)
read (unit,*,pos=pos) buffer
write (*,*) "buffer=", trim(buffer)
! Close file stream
close (UNIT=unit)
end program main