Fortran reads outside the record

I am trying to read some data from a file, and detection of the final file entry is important to stop reading. However, depending on the size of the array of the array used to read the data, I cannot correctly determine the record of the destination file, and my Fortran program stops.

The program is below:

!integer, dimension(3) :: x ! line 1.1 !integer, dimension(3,10) :: x ! line 1.2 integer, dimension(10,3) :: ! line 1.3 integer :: status,i=1 character(len=100) :: error open( 30, file='data.dat', status='old' ) do print *,i !read( 30, *, iostat=status, iomsg=error ) x ! line 2.1 !read( 30, *, iostat=status, iomsg=error ) x(:,i) ! line 2.2 read( 30, *, iostat=status, iomsg=error ) x(i,:) ! line 2.3 if ( status < 0 ) then print *,'EOF' print *,'total of ',i-1,' lines read.' exit else if ( status > 0 ) then print *,'error cod: ',status print *,'error message: ', error stop else if ( status == 0 ) then print *,'reading ok.' i = i + 1 end if end do 

With the data.dat file was:

 10 20 30 30 40 50 

When lines 1.3 and 2.3 are uncommented, the following error appears:

error cod: 5008

error message: Read last entry ENDFILE

However, using lines 1.1 and 2.1, or 1.2 and 2.2, the program works by detecting the record of the final file.

So, I would like to help a little to understand why I cannot use lines 1.3 and 2.3 to read this file correctly, since I am giving the correct number of array elements for the read command.

I am using the gfortran compiler, version 6.3.0.

EDIT: A Simpler Example

the following results in error 5008 "Read past ENDFILE error":

 implicit none integer x(2,2),s open(20,file='noexist') read(20,*,iostat=s)x write(*,*)s end 

if we make x scalar or one-dimensional array (any size), we get the expected flag -1 EOF. It doesn't matter if the file really does not exist or is empty. If the file contains some but not enough data, it is difficult to understand what return value you can get.

+5
source share
2 answers

I'm not sure if I am expressing myself correctly, but this is due to the way fortran reads and stores 2d arrays. When you use this notation: x(:,i) , column i actually expands in the row and the elements are read using this single line of code. In the other case, when x(i,:) , line i read as if you had called read several times. You can use implicit loops if you want to stick to a specific shape and size. For example, you can use something like this: read( 30, *, iostat=status, iomsg=error ) (x(i,j), j=1,3)

In any case, you should verify that your data is stored correctly (as expected, at least) in the variable x .

-1
source

Please note that this is just an assumption. Remember that Fortran stores arrays in the main column order. When gfortran compiles read() x(:,i) , 3 memory cells are next to each other, so in the executable file it issues one call to the operating system to read from 3 values ​​from the file.

Now that read() x(i,:) compiled, the three data elements x(i,1) , x(i,2) and x(i,3) not in continuous memory. Therefore, I assume that the executable actually has 3 call reads in the operating system. The first one would catch the EOF trap, but the second gave you the read past end of the file error.

UPDATE: I confirmed that this does not happen with Intel ifort. It seems that there was a similar problem before gfortran : Bad IOSTAT values ​​when reading NAMELIT past EOF . Whether this is a mistake or not is debatable. The code, of course, looks like it should catch EOF.

-1
source

Source: https://habr.com/ru/post/1275666/


All Articles