In fortran how to read all strings line by line from a .dat file in fortran
Solution 1
There are a few things I notice straight away:
- The line
read(*, *) command(i)
reads the first element of standard input, not from the file. I think you want toread(9, *)
. - Actually, you'll probably want to
read(9, '(A)')
because you want to read the whole line, not just until the first element separator (i.e. space or comma). In your subroutine, you open the file again, under the same unit. That is... dangerous if not wrong. Better to just read from the file, then use the
rewind
command to move the read position back to the beginning of the file.program atom_test implicit none integer :: ios integer, parameter :: read_unit = 99 character(len=200), allocatable :: command(:) character(len=200) :: line integer :: n, i open(unit=read_unit, file='data.dat', iostat=ios) if ( ios /= 0 ) stop "Error opening file data.dat" n = 0 do read(read_unit, '(A)', iostat=ios) line if (ios /= 0) exit n = n + 1 end do print*, "File contains ", n, "commands" allocate(command(n)) rewind(read_unit) do i = 1, n read(read_unit, '(A)') command(i) end do close(read_unit) do i = 1, n print*, command(i) end do end program atom_test
If you already dedicate 3000 lines in the beginning, there's no real reason to read everything twice:
program atom_test implicit none integer :: ios integer, parameter :: read_unit = 99 character(len=200) :: command(3000) integer :: n, i open(unit=read_unit, file='data.dat', iostat=ios) if ( ios /= 0 ) stop "Error opening file data.dat" n = 0 do read(read_unit, '(A)', iostat=ios) command(n+1) if (ios /= 0) exit n = n + 1 end do print*, "File contains ", n, "commands" close(read_unit) do i = 1, n print*, command(i) end do end program atom_test
In your subroutine to read the number of lines in the file, you try to read a
REAL
from a file where the first word is often not a number. This might lead toIOSTAT
being non-zero, even if you haven't reached the end of the file. Always read acharacter
variable.
Solution 2
This post provides an answer to OP comment:
I want to get the elements separately from the ATOM rows in my data file
Assuming input.txt
looks like:
ATOM 1 S2 LJ2 1 17.000 15.030 11.630 1.00 0.00
ATOM 2 S2 LJ2 2 13.290 11.340 15.900 1.00 0.00
ATOM 3 S2 LJ2 3 17.030 23.070 14.750 1.00 0.00
ATOM 4 S2 LJ2 4 15.360 14.840 9.480 1.00 0.00
ATOM 5 S2 LJ2 5 15.780 4.560 9.580 1.00 0.00
ATOM 6 S2 LJ2 6 5.350 22.490 11.110 1.00 0.00
ATOM 7 S2 LJ2 7 19.940 3.910 10.840 1.00 0.00
ATOM 8 S2 LJ2 8 20.380 13.360 15.680 1.00 0.00
ATOM 9 S2 LJ2 9 18.340 4.200 7.720 1.00 0.00
ATOM 10 S2 LJ2 10 18.610 16.530 9.910 1.00 0.00
You could
- read columns into strings
- read real numbers from strings
- output the results
program fort
integer n, i
parameter (n=10)
real r1(n), r2(n), r3(n), r4(n), r5(n), r6(n), r7(n)
character(len=255) format, s1(n), s2(n), s3(n), s4(n), s5(n),
& s6(n), s7(n), s8(n), s9(n), s10(n)
i=1
open(unit=99, file='input.txt')
2 read(99,3,end=1) s1(i), s2(i), s3(i), s4(i), s5(i),
& s6(i), s7(i), s8(i), s9(i), s10(i)
i=i+1
goto 2
3 format(a6,2a4,a5,a4,3a8,a6,a4)
4 format(a6,f4.1,2x,2a4,f4.1,5f8.3)
1 close(99)
read(s2,*) r1
read(s5,*) r2
read(s6,*) r3
read(s7,*) r4
read(s8,*) r5
read(s9,*) r6
read(s10,*) r7
do i=1,n
write(*,4) s1(i), r1(i), s3(i), s4(i), r2(i),
& r3(i), r4(i), r5(i), r6(i), r7(i)
enddo
end
output:
ATOM 1.0 S2 LJ2 1.0 17.000 15.030 11.630 1.000 0.000
ATOM 2.0 S2 LJ2 2.0 13.290 11.340 15.900 1.000 0.000
ATOM 3.0 S2 LJ2 3.0 17.030 23.070 14.750 1.000 0.000
ATOM 4.0 S2 LJ2 4.0 15.360 14.840 9.480 1.000 0.000
ATOM 5.0 S2 LJ2 5.0 15.780 4.560 9.580 1.000 0.000
ATOM 6.0 S2 LJ2 6.0 5.350 22.490 11.110 1.000 0.000
ATOM 7.0 S2 LJ2 7.0 19.940 3.910 10.840 1.000 0.000
ATOM 8.0 S2 LJ2 8.0 20.380 13.360 15.680 1.000 0.000
ATOM 9.0 S2 LJ2 9.0 18.340 4.200 7.720 1.000 0.000
ATOM 10.0 S2 LJ2 10.0 18.610 16.530 9.910 1.000 0.000
A better approach consists on
- read columns into variables (strings, integers, or reals)
- output the results
program fort
integer n, i
parameter (n=10)
integer i1(n), i2(n)
real r1(n), r2(n), r3(n), r4(n), r5(n)
character(len=255) format, s1(n), s2(n), s3(n), s4(n), s5(n),
& s6(n), s7(n), s8(n), s9(n), s10(n)
i=1
open(unit=99, file='input.txt')
2 read(99,3,end=1) s1(i), i1(i), s3(i), s4(i), i2(i),
& r1(i), r2(i), r3(i), r4(i), r5(i)
i=i+1
goto 2
3 format(a6,i4,a4,a5,i4,3f8.3,2f6.2)
4 format(a6,i4,2x,2a4,i4,5f8.3)
1 close(99)
do i=1,n
write(*,4) s1(i), i1(i), s3(i), s4(i), i2(i),
& r1(i), r2(i), r3(i), r4(i), r5(i)
enddo
end
Samudranil Roy
Updated on July 02, 2022Comments
-
Samudranil Roy over 1 year
I have a .dat file , from which I am trying to read line by line and print it. Can anyone please help about how to do it in fortran?
Thanks in advance!
Data:
REMARK GENERATED BY TRJCONV TITLE UNNAMED t= 0.00000 REMARK THIS IS A SIMULATION BOX CRYST1 26.178 26.178 26.178 90.00 90.00 90.00 P 1 1 MODEL 1 ATOM 1 S2 LJ2 1 17.000 15.030 11.630 1.00 0.00 ATOM 2 S2 LJ2 2 13.290 11.340 15.900 1.00 0.00 ATOM 3 S2 LJ2 3 17.030 23.070 14.750 1.00 0.00 ATOM 4 S2 LJ2 4 15.360 14.840 9.480 1.00 0.00 ATOM 5 S2 LJ2 5 15.780 4.560 9.580 1.00 0.00 ATOM 6 S2 LJ2 6 5.350 22.490 11.110 1.00 0.00 ATOM 7 S2 LJ2 7 19.940 3.910 10.840 1.00 0.00 ATOM 8 S2 LJ2 8 20.380 13.360 15.680 1.00 0.00 ATOM 9 S2 LJ2 9 18.340 4.200 7.720 1.00 0.00 ATOM 10 S2 LJ2 10 18.610 16.530 9.910 1.00 0.00 TER ENDMDL
Code:
program atom_test implicit none character (LEN=75) ::inputdatafile,outputfile real,dimension(100) :: x, y integer :: i,n,nframes character (len=200),dimension(3000):: command print *,"Give the datafile name:" read *,inputdatafile outputfile=inputdatafile(1:len(trim(inputdatafile))-4)//"_output.dat" !write(*,*)outputfile Open(9, file=inputdatafile, status='old') call linesFile(inputdatafile,n) write(*,*)n do i=1,n read(*,*),command(i) write (*,*)command(i) end do close(9) end program atom_test !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! find the number of lines in a file !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine linesFile(fileIn,n) implicit none Character(len = 50) :: fileIn integer, intent(out) :: n ! locals integer :: iostatus, unit_read real :: dummy unit_read = 9 open(unit=unit_read, file=fileIn) n =0 DO READ(unit_read, *, IOSTAT=iostatus) dummy IF (iostatus < 0) EXIT n = n + 1 END DO ! WRITE(*, '(i8, a, a)') n, ' bins read from file: ', fileIn close(unit_read) end subroutine linesFile
Given marked answer works fine. As I am very new in Fortran I have one more question related this. I want to get the elements separately from the ATOM rows in my data file for example: ATOM 1 S2 LJ2 1 17.000 15.030 11.630 1.00 0.00
from here i want to store 1,s2,LJ2,1,17.000,15.030 each in different parameters. In that case I am using this
/* With the code marked as correct
ncount=0 do i = 1, n IF (command(i)(1:4).eq.'ATOM') THEN ncount=ncount+1 read(read_unit,*) p, p2, p3,p4,xatom(ncount) write(*,*),p endif end do
But it is not working.Can you please give me one suggestion about how to read individually from those lines which starts with ATOM? Thanks in advance!
-
Samudranil Roy over 6 yearsHi , Thanks a lot . That works fine. As I am very new in Fortran I have one more question related this. I want to get the elements separately from the ATOM rows in my data file