Fortran: чтение и печать 2D-массива из текстового файла - PullRequest
0 голосов
/ 01 апреля 2020

Я новичок в Fortran, и все, что я пытаюсь сделать, это прочитать массив 3x3 и распечатать его, но я получаю сообщение об ошибке конца строки:

Текстовый файл содержит следующий массив:

1 2 3

4 5 6

7 8 9

Вот мой код:

program myfile
implicit none 

! Declare Variables
integer i,j
!real, dimension(1:3,1:3) :: A
integer, parameter :: M = 3, N =3
real, dimension(1:M,1:N) :: A

! Open and read data
open(unit=10, file = 'test_file_cols.txt', status = 'old')
do i =1,M
    do j =1,N
        read(unit=10,FMT=*) A(i,j)
        print *,A(i,j)
    end do
end do      

end program myfile

Я получаю ошибку ниже:

1.000000

4.000000

7.000000

forrtl: строгое (24): конец файла во время чтения, блок 10, файл C: \ Users \ M42141 \ Documents \ mean_flow_file \ test_file_cols.txt

1 Ответ

4 голосов
/ 01 апреля 2020

Как кратко обсуждалось в комментариях, по умолчанию все операции ввода-вывода в Fortran основаны на записях. Это верно как для форматированных, так и для неформатированных файлов. Что происходит, файл рассматривается как набор записей - и вы можете думать о записи как о строке в файле. Теперь эти строки могут быть очень и очень длинными, особенно в неформатированных файлах, но методология ввода-вывода Fortran по-прежнему рассматривает их как набор строк.

Теперь важно то, что по умолчанию каждый раз, когда вы выполнить оператор ввода-вывода (чтение, запись, печать), последнее, что он делает, - это перейти от записи, к которой он относится, к следующей записи - оператор записи запишет маркер конца записи. Вот почему вы автоматически получаете новую строку после оператора записи, но это также означает, что для оператора чтения все оставшиеся в записи данные (в строке) будут пропущены. Это то, что происходит с вами. Первое чтение читает запись 1, и вы получаете 1.0, а затем переходит на запись 2. Затем ваша программа читает запись 2, и вы получаете 4.0, и она автоматически переходит на запись 3. Затем читается (9.0) и файл указатель перемещается на запись 4. Затем вы пытаетесь прочитать это, но записи 4 нет, поэтому вы получаете ошибку конца файла.

Структура записи немного странная, когда вы впервые сталкиваетесь с ней, но когда вы привыкнете к нему, это очень мощно и удобно - я покажу пример ниже, а другой может быть, что вы можете оставить комментарий в конце каждой строки, сообщая, что он делает, конец оператора read будет означает, что вы переходите к следующей записи, поэтому пропустите комментарий и вам не нужно предпринимать никаких специальных действий в своем коде, чтобы разобраться с таким случаем.

В любом случае, как решить ваше дело. Три возможных способа

  1. Чтение всей записи за раз - в комментарии предлагается подразумеваемый do l oop, но я думаю, что в этом случае секция массива намного проще и интуитивнее
  2. Вы можете просто прочитать весь массив в одном go. Это работает, потому что когда оператор чтения завершает запись и находит, что ему все еще «нужно» больше данных, он перенесет в следующую запись и продолжит чтение. Но обратите внимание, что идея с комментариями в конце строки здесь не сработает - вы можете понять почему?
  3. Не продвигающийся ввод / вывод. Я не рекомендую это вообще в этом случае, но для полноты это позволяет вам выполнять чтение или запись без перехода к следующей записи

Могут быть и другие, вы, вероятно, можете использовать так называемые Потоковый ввод-вывод, но лично я предпочитаю, когда это возможно, основывать записи, я считаю это более удобным и мощным. В любом случае, вот программа, иллюстрирующая 3 метода. Заметьте, что я также изменил ваш входной файл, заставить оригинал работать с неразвитым вводом-выводом - боль, но не другие 2 - еще одна причина не использовать его здесь.

ian@eris: ~ / работа / стек $ cat readit.f90

Program readit

  Implicit None

  Real, Dimension( 1:3, 1:3 ) :: a

  Integer :: i, j

  ! one line per read
  Write( *, * ) 'Line at a time'
  Open( 10, file = 'in' )
  Do i = 1, 3
     Read ( 10, * ) a( i, : )
     Write(  *, * ) a( i, : )
  End Do
  Close( 10 )

  ! All in one go
  Write( *, * ) 'All in one go'
  Open( 10, file = 'in' )
  Read ( 10, * ) a
  Write(  *, * ) a
  Close( 10 )

  ! Non advancing I/O
  Write( *, * ) 'Non-advancing'
  Open( 10, file = 'in' )
  Do i = 1, 3
     Do j = 1, 3
        ! Non advancing I/O requires a 'proper' format
        Read ( 10, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
        Write(  *, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
     End Do
     ! Move to next records (lines)
     Read ( 10, * )
     Write(  *, * )
  End Do
  Close( 10 )

End Program readit
ian@eris:~/work/stack$ gfortran-8 -Wall -Wextra -pedantic -std=f2008 -fcheck=all -O readit.f90
ian@eris:~/work/stack$ cat in
1.0 2.0 3.00 
4.0 5.0 6.00 
7.0 8.0 9.00 

ian@eris:~/work/stack$ ./a.out
 Line at a time
   1.00000000       2.00000000       3.00000000    
   4.00000000       5.00000000       6.00000000    
   7.00000000       8.00000000       9.00000000    
 All in one go
   1.00000000       2.00000000       3.00000000       4.00000000       5.00000000       6.00000000       7.00000000       8.00000000       9.00000000    
 Non-advancing
1.0 2.0 3.0 
4.0 5.0 6.0 
7.0 8.0 9.0 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...