Reading data file in Fortran with known number of lines but unknown number of entries in each line

11,249

Solution 1

One method: read the line into a string, using a string that is at least as long as the longest expected line. Then you go about parsing the string. E.g., if the numbers are always split by spaces, use that to figure out the substring boundaries. Then you can use "internal reads" to read from each sub-string to obtain the numeric values. An internal read uses a string instead of a unit number and obtains the data from the string -- at least you don't have to recreate the conversion of characters to numeric values, the read statement will do that for you. The intrinsic functions provided with Fortran will make the parsing easier.

Solution 2

An implementation based on what M. S. B. pointed out. Quite late, but I guess it could be useful to someone.

Have an array of the type you expect to read ready:

double precision, dimension(MAX_NUM_OF_COLS) :: test_array

Read a line from your file:

READ(reading_unit,'(A)',iostat=io) line

Loop and try to read from the line a maximum quantity of numbers:

do i=1,MAX_NUM_OF_COLS
  READ(line, *, iostat=io) test_array(1:i)
  if(io==0) exit
enddo

write(*,*) 'number of columns = ', (i-1)

If needed, loop this over all the lines of your file, and keep the maximum or minimum number of columns.

Minimum example:

integer, parameter :: MAX_NUM_OF_COLS=30
integer, parameter :: MAX_LINE_LENGTH=1000
character(len=MAX_LINE_LENGTH) line
integer i, io, reading_unit
double precision, dimension(MAX_NUM_OF_COLS) :: test_array

reading_unit=100
OPEN(reading_unit, file='the_file')

! Get first line of file.
DO
  READ(reading_unit,'(A)',iostat=io) line
  IF (io/=0) then
    write(*,*) "Error reading file."
    stop
  endif
  exit ! Eventually, do not exit and put the DO loop below here.
ENDDO
CLOSE(reading_unit)

do i=1,MAX_NUM_OF_COLS
  READ(line,*,iostat=io) test_array(1:i)
  if(io==-1) exit
enddo

write(*,*) 'number of columns = ', (i-1)

Solution 3

Assuming that you're okay with padding the array with zeros (specifically referring to the later duplicate question here), this is my idea:

Read the data line by line into a string, then append a number of zeros, finally read each row of the data from this array. Here's an example:

program unknown_numbers

    implicit none
    integer, parameter :: nrow=3, ncol=14
    integer :: data(ncol, nrow)
    character(len=2*ncol) :: zeros ! will contain lots of zeros
    character(len=10*ncol) :: line ! temporary storage for each line of the file
    integer :: i, u

    ! Write " 0 0 0 0 0 0 0 0" into the string "zeros"
    write(zeros, '(*(I2))') [(0, i=1, ncol)]

    open(newunit=u, file='data.txt', status='old', action='read')

    do i = 1, nrow, 1
        ! Read the next line into a temporary string array
        read(u, '(A)') line
        ! Append a number of zeros to the temporary string
        line = trim(line) // zeros
        ! Read the row of data from the string.
        read(line, *) data(:, i)
    end do

    close(u)

    ! For testing purposes, print the data.
    print '(14(X, I3))', data

end program unknown_numbers

Solution 4

integer,parameter :: reclen=99999        ! maximum record length
integer,parameter :: undef=-9999         ! undefined value
integer :: actual_reclen                 ! actual record length
integer,dimension(reclen) :: dummy=undef ! dummy array used for reading
integer,dimension(:),allocatable :: a    ! final array

open(unit=10,file='sample.txt',form='formatted',access='sequential')
read(unit=10,fmt=*,end=101)(dummy(i),i=1,reclen)
101 close(unit=10)

actual_reclen=COUNT(dummy/=undef)
allocate(a(actual_reclen))
a=dummy(1:actual_reclen)

end
Share:
11,249
Zahur
Author by

Zahur

Updated on June 26, 2022

Comments

  • Zahur
    Zahur almost 2 years

    How can I read the data file containing known number of lines but the number of entries in each line is unknown, e.g. if my data file contain some thing like

    1 3 4 5 6 -7 8 -9

    1 3 5 6

    4 5 6 7 8 3 5 6 7 8 4 5 7 8

    i.e. three lines but the data in each line is unknown. At one time I need the data from one line.

  • Zahur
    Zahur over 12 years
    Thank you very much for your reply, this will read all the data in the file instead of line by line. I used the method suggested by MSB and it is working fine
  • Admin
    Admin about 7 years
    this is the program that can count numbers in a line(or number of columns) but for a line.if you have many lines ,you should change it slightly
  • Vladimir F Героям слава
    Vladimir F Героям слава about 7 years
    Welcome, try to always format your posts properly and also comment what the lines you used in the program do and why are they the correct solution. Also you should use consistent indentation i your codes and avoid so many goto's. Goto is considered harmful by many.
  • agentp
    agentp about 7 years
    you really should consider if a question has an accepted answer 6 years ago, what are you contributing?
  • agentp
    agentp about 6 years
    pretty slick. Only drawback here is you wont know if there were actual zeros in the file or your padding.
  • chw21
    chw21 about 6 years
    You're right. I came here from a more recent question where padding with zeros was the desired behaviour, but which was declared a duplicate of this question.