Fortran: Reading and printing 2D array from text file

那年仲夏 提交于 2021-02-17 06:22:27

问题


I am new to fortran and all I am trying to do is read a 3x3 array and print it out but I am getting an end of line error:

The text file contains the following array:

1 2 3

4 5 6

7 8 9

Here is my code:

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

The error I am getting is below:

1.000000

4.000000

7.000000

forrtl: severe (24): end-of-file during read, unit 10, file C:\Users\M42141\Documents\mean_flow_file\test_file_cols.txt


回答1:


As discussed briefly in the comments by default all I/O in Fortran is record based. This is true for both formatted and unformatted files. What happens is the file is viewed as a set of records - and you can think of a record as a line in the file. Now these lines may be very, very long, especially in an unformatted files, but the default Fortran I/O methodology still views it as a set of lines.

Now the important thing is that by default every time you perform an I/O statement (read, write, print) the last thing it does is move from the record it is on to the next record - a write statement will write an end of record marker. This is why you automatically get a newline after a write statement, but it also means that for a read statement any remaining data in the record (on the line) will get skipped over. This is what is happening to you. The first read reads record 1, and so you get 1.0, and then moves to record 2. Your program then reads record 2 and so you get 4.0, and it automatically moves to record 3. this is then read (9.0) and the file pointer moves onto record 4. You then try to read this, but there isn't a record 4, so you get an end of file error.

Record structure is a bit strange when you first encounter it, but when you get used to it it is very powerful and convenient - I'll show an example below, and another one might be that you could leave a comment at the end of each line saying what it does, the end of the read statement will mean you move to the next record, so skipping the comment and needing to take no special action in you code to deal with such a case.

Anyway how to solve your case. Three possible ways

  1. Read a whole record at a time - the comment suggests an implied do loop but I think in this case an array section is much easier and more intuitive
  2. You can simply read the whole array in one go. This works because when a read statement finishes a record and finds it still "needs" more data it will carry onto the next record and keep reading. But note the end of line comment idea won't work here - can you work out why?
  3. Non-Advancing I/O. I don't recommend this at all in this case, but for completeness this allows you to perform a read or write without moving onto the next record

There may be others, you could probably use so called stream I/O but personally I prefer record based whenever possible, I find it more convenient and powerful. Anyway here is a program illustrating the 3 methods. Note I have also changed your input file, getting the original to work with non-advancing I/O is a pain, but not the other 2 - another reason not to use it here.

ian@eris:~/work/stack$ 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 


来源:https://stackoverflow.com/questions/60961633/fortran-reading-and-printing-2d-array-from-text-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!