Извлечь указанную строку из файла с помощью Fortran - PullRequest
0 голосов
/ 16 февраля 2019

Я пытаюсь написать функцию, которая извлекает указанную строку из заданного файла.Моя функция для этого принимает два аргумента:

  1. fUnit: это числовой идентификатор данного файла.
  2. fLine: это номер строки, которую я хотел бы извлечь,Если значение этого ввода равно -1, то функция вернет последнюю строку файла (в моей работе эта функция мне нужна больше всего).

Я обернул эту функциювнутри модуля ( рутины.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 голосов
/ 17 февраля 2019

Положение подключенного внешнего файла - состояние global .В этом случае функция getline изменяет положение файла после его поиска.В следующий раз, когда вызывается функция, поиск начинается с позиции, в которой она была оставлена.

То, что вы видите, это не столько «пропуск» строк, сколько:

  • в первой итерации читается первая строка;
  • во второй итерации пропускается строка (вторая), затем читается строка (третья);
  • в третьейитерация, две строки пропускаются, а третья пытается прочитать.

Однако третья строка в третьей итерации ( шестая файла) находится после концаусловиеВы видите результат чтения пятой строки.

Чтобы включить поиск по своему желанию, убедитесь, что вы поместили файл в его начальную точку, прежде чем пропустить строки.Оператор rewind помещает подключенный файл в его начальное положение.

Вместо перемотки вы можете закрыть файл и открыть его снова с помощью position='rewind', чтобы убедиться, что он расположен в начальной точке, но rewind оператор - лучший способ изменить положение.Если вы снова откроете без спецификатора position=, вы увидите эффект, подобный position='asis'.Это оставляет позицию в файле, не определенную стандартом Fortran.

0 голосов
/ 17 февраля 2019

После помощи @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

рутины.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 
...