1

I am trying to read a text file using a Fortran code. I have a file with 1999 rows and the number of columns vary with each row. Can someone please tell me how one can code such a problem. This is my code for reading a 4*2 text file but I am using do loops which I can't use in my current case.

PROGRAM myread2
IMPLICIT NONE

  INTEGER, DIMENSION(100) :: a, b
  INTEGER :: row,col,max_rows,max_cols

  OPEN(UNIT=11, file='text.txt')

  DO row = 1,4
    READ(11,*) a(row), b(row)
  END DO
  PRINT *, a(1)
  PRINT *, a(4)
  PRINT*, b(4)
END PROGRAM myread2
6
  • Why do you want to use a while loop? What features does a while loop give you that a normal do loop doesn't? Do you want to read data while there is some still to be read in the file? Commented Jul 26, 2021 at 9:02
  • @IanBush I am trying to read a file with a 1999 rows and the number of columns varies. I am not sure how to use a do loop in this case and hence thought maybe while loop might solve my problem. Commented Jul 26, 2021 at 9:05
  • 1
    I think you want to read each row as a string (or character) and then split using something like scivision.github.io/fortran2018-examples/sourcefile/… and convert to integers with iachar Commented Jul 26, 2021 at 9:34
  • 1
    That would be my guess from the description, except convert to integers via an internal file, which is the way to do it in Fortran Commented Jul 26, 2021 at 10:00
  • 1
    @veryreverie That (seems to) assume the number of columns is the same in each row. This question explicitly says the number of columns varies. That's potentially much more tricky Commented Jul 27, 2021 at 7:38

1 Answer 1

1

The best way of reading a file like this depends on how you want to store the data. I'm going to use a ragged array as it's probably simplest, although other container types may be better suited depending on your requirements.

Fortran doesn't have ragged arrays natively, so first you need to define a type to hold each row. This can be done as

type :: RowData
  integer, allocatable :: cols(:)
end type

type(RowData), allocatable :: rows(:)

When this container is filled out, the value in the i'th column of the j'th row will be accessed as

value = rows(j)%cols(i)

We can then write a program to read the file, e.g.

type :: RowData
  integer, allocatable :: cols(:)
end type

type(RowData), allocatable :: rows(:)

integer :: no_rows
integer :: i

open(unit=11, file='text.txt')

no_rows = count_lines(11)
allocate(rows(no_rows))

do i=1,no_rows
  rows(i)%cols = read_row(11)
enddo

Now we just need to write the functions count_lines, which counts the number of lines in the file, and read_row, which reads a line from the file and returns the contents of that line as an array of integers.

Following this question, count_lines can be written as

! Takes a file unit, and returns the number of lines in the file.
! N.B. the file must be at the start of the file.
function count_lines(file_unit) result(output)
  integer, intent(in) :: file_unit
  integer :: output
  
  integer :: iostat
  
  output = 0
  iostat = 0
  do while (iostat==0)
    read(file_unit, *, iostat=iostat)
    if (iostat==0) then
      output = output+1
    endif
  enddo
  rewind(file_unit)
end function

Writing read_row, to parse a line of unknown length from a file, can be done by following this question.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.