Search code examples
file-iofortrantext-files

reading text file columns one after another in a 1D array


I have tried to read the following text file using Fortran. The text file has 24 rows and 15 columns. I want to put all the data in a single column array z. I wanted to read the 1st column then the 2nd then 3rd until the end. Here is my data:

1   0   0   0   0   0   0   0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
0   0   0   0.16    0.16    0.17    0.18    0.19    0.19    0.19    0.19    0.18    0.18    0.18    0.18
0   0   0   0.31    0.33    0.35    0.37    0.37    0.39    0.39    0.37    0.37    0.37    0.37    0.37
0   0   0   0.47    0.49    0.52    0.55    0.56    0.58    0.58    0.56    0.55    0.55    0.55    0.55
0   0   0   0.48    0.51    0.55    0.59    0.6 0.61    0.61    0.59    0.59    0.59    0.59    0.59
0   0   0   0.48    0.53    0.57    0.62    0.63    0.64    0.63    0.62    0.62    0.62    0.62    0.62
10  34  0   0.49    0.55    0.6 0.66    0.68    0.69    0.68    0.67    0.67    0.67    0.67    0.67
0   0   0   0.49    0.57    0.63    0.7 0.72    0.73    0.73    0.72    0.72    0.72    0.72    0.72
0   0   0   0.49    0.59    0.65    0.75    0.77    0.78    0.77    0.77    0.77    0.77    0.77    0.77
0   0   0   0.49    0.61    0.68    0.79    0.81    0.83    0.82    0.81    0.82    0.82    0.82    0.82
0   0   0   0.49    0.63    0.7 0.83    0.86    0.87    0.87    0.86    0.87    0.87    0.87    0.87
0   0   0   0.49    0.65    0.73    0.87    0.9 0.92    0.92    0.91    0.92    0.92    0.92    0.92
0   0   0   0.49    0.67    0.76    0.91    0.95    0.97    0.96    0.95    0.97    0.97    0.97    0.97
0   0   0   0.49    0.69    0.78    0.95    0.99    1.01    1.01    1   1.02    1.02    1.02    1.02
0   0   0   0.49    0.71    0.81    0.99    1.04    1.06    1.06    1.05    1.07    1.07    1.07    1.07
0   0   0   0.49    0.73    0.83    1.04    1.08    1.11    1.1 1.09    1.11    1.11    1.11    1.11
0   0   0   0.49    0.75    0.86    1.08    1.13    1.15    1.15    1.14    1.16    1.16    1.16    1.16
0   0   0   0.49    0.77    0.88    1.12    1.18    1.2 1.2 1.19    1.21    1.21    1.21    1.21
0   0   0   0.49    0.77    0.88    1.12    1.18    1.2 1.2 1.19    1.21    1.21    1.21    1.21
0   0   0   0.49    0.77    0.88    1.12    1.18    1.2 1.2 1.19    1.21    1.21    1.21    1.21
24  48  72  0.49    0.77    0.88    1.12    1.18    1.2 1.2 1.19    1.21    1.21    1.21    1.21

Here is the code I tried:

program readdata
  use, intrinsic :: iso_fortran_env
  implicit none

  integer :: i, j, k
  real :: z(360)
  integer :: iostat
  character(len=255) :: filename

  ! Set the text file name
  filename = 'D:/Shuvashish/Oyster Shaye/growth_z_for_sal_tem.txt'

  ! Open the text file
  open(15, file=filename, status='old',form='formatted')

  ! Read the data from the text file into the z array
  k = 1
  do j = 1, 15   ! j is changing
    do i = 1, 24 ! when j=2 and k=25, iostat becomes -1
      read(15,*,iostat=iostat) z(k)
      if (iostat < 0) exit ! exit loop if iostat is negative
      k = k + 1
    end do

  end do

  ! Close the text file
  close(15)

  ! Print the values of z
  do k = 1, 360
    print*, z(k)
  end do

end program readdata

Whenever, the loop finishes reading the last element of the 1st column, iostat becomes -1 and after that the it doesn't read the other columns. I am an absolute begineer in Fortran. Please let me know how to make the code work. Thanks.


Solution

  • When you write

    read(15,*,iostat=iostat) z(k)
    

    you will actually read an entire row ... but you will discard all but the first element. Thus, you can only do this 24 times and you will end up only storing the first column.

    But when we read or write text we read from left to right (apologies to Leonardo da Vinci and anybody else writing from right to left!) and do so line by line. Similarly for computer files.

    So, if you insist on reading into a 1-d array, (actually, you might find life easier if you read into a 2-d array), then read it ROW-BY-ROW first, then "transpose" to COLUMN-BY-COLUMN afterwards. (To be honest, do you really have to store your data column by column? You could easily have the i index denoting a column rather than a row.)

    To read that file and subsequently store it in a 1-d array as first column, followed by second column, followed by third column etc, try the following.

    program readdata
      implicit none
    
      integer, parameter :: ni = 24, nj = 15
      character(len=*), parameter :: filename = "input.txt"
    
      integer i, j
      real rowByRow(ni*nj), columnByColumn(ni*nj)
    
      ! Read the text file ROW-BY-ROW
      open( 15, file=filename )
      read( 15, * ) rowByRow
      close( 15 )
    
      ! Transpose it to store COLUMN-BY-COLUMN
      do j = 1, nj
         columnByColumn( (j-1)*ni+1 : j*ni ) = rowByrow( j : : nj )
      end do
    
      ! Test write
      j = 5
      print "( a, i0 )", "Column ", j
      print "( f5.2 )", columnByColumn( (j-1)*ni + j : j*ni )
    
    end program readdata
    

    For example, the 5th column:

    Column 5
     0.16
     0.33
     0.49
     0.51
     0.53
     0.55
     0.57
     0.59
     0.61
     0.63
     0.65
     0.67
     0.69
     0.71
     0.73
     0.75
     0.77
     0.77
     0.77
     0.77