The easiest way is like this (reverse the order of indexes for row and column if necessary and add declarations for all variables I skipped to keep it short). It first reads the file and determines the number of lines. Then it rewinds the file to start from the beginning and reads the known number of lines.
integer,allocatable :: a(:,:)
integer :: pair(2)
integer :: unit
unit = 11
open(unit,file="test.txt")
n = 0
do
read(unit,*,iostat=io) pair
if (io/=0) exit
n = n + 1
end do
rewind(unit)
allocate(a(n,2))
do i=1,n
read(unit,*) a(i,:)
end do
close(unit)
print *, a
end
The check if (io/=0) exit
is generic and will trigger on any error or end of record/file condition encountered.
Fortran 2003 contains constants specific constants in the iso_fortran_env
module that contain specific values the iostat=
can have.
IOSTAT_END:
The value assigned to the variable passed to the IOSTAT= specifier of an input/output statement if an end-of-file condition occurred.
IOSTAT_EOR:
The value assigned to the variable passed to the IOSTAT= specifier of an input/output statement if an end-of-record condition occurred.
So if you only want to check for the end of file condition, use
if (io/=iostat_end) exit
end use
the iso_fortran_env
module before.
One pass solution also can be done, using temporary array you can grow the array easily (the C++ vector does the same behind the scenes). You could even implement your own grow able class, but it is out of scope of this question.
If you have a long fixed-size array with your data and not an allocatable one, you can skip the first pass and just read the file with the iostat=
specifier and finish reading when it is nonzero or equal to iostat_end
.