Reputation: 306
If I use Fortran to write and read a file in the same manner with stream it works well. If I edit the file with a text editor without changing anything (like return then backspace) and save the file it will not read, quoting end of file before the position I expect it to end.
To investigate, I wrote the following code which writes my table then reads it in one position at a time as a character. It only works correctly if there are no new lines in the file I am reading from. Otherwise, I only get the last n numbers, n being the amount of data per line.
The idea is to learn more powerful ways than sequential read to read in large strangely formatted data files I use at work that come from engineering software and test equipment.
program stream
implicit none
character(len=1) :: text
integer(kind=4), dimension(100) :: array
integer(kind=4) :: status = 0, i
open (unit=11, file='out.txt', form='formatted', access='stream', action='readwrite', status='replace')
array = (/(i, i = 1,100)/) ! Populate vector from 1 to 100
write(unit=11,fmt='(10i4)') array ! Write array to file
i=0
do while ( status == 0) ! Read array back from file, one position at a time until end of file
i=i+1
read(unit=11, fmt='(a1)', pos=i, iostat=status) text
write(*,fmt='(a1)', advance='no') text ! Write results to screen to see what is in each position
end do
close(unit=11)
end program stream
File written then read:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
Result: (many spaces here)
8 8 8 8 8 8 8 8 9 91 92 93 94 95 96 97 98 99 100
Upvotes: 4
Views: 1214
Reputation: 21431
I think what you are seeing is an issue with the compiler runtime, exacerbated by choices you have made with your program.
With formatted stream, a read statement without an ADVANCE specifier advances to the next record, just like a READ with a formatted sequential file. Because of the format specification associated with the READ, you then discard all but the first character read, but the underlying file position is still changed.
Because you have a POS specifier with the READ, each READ then requires the runtime to move backwards from the end of record to your next character of interest. The compiler's runtime is not correctly handling this.
But there is no need for you to do this constant jumping back and forwards in the file - instead, prior to reading reposition the file at its initial point (perhaps using REWIND) and then use non advancing input without the POS specifier to progressively step through the file character by character. You will need to appropriately handle the IOSTAT_EOR status code when the end of a particular record is reached.
Note also that for formatted stream, there is no guarantee (it is processor dependent) that all positive integers correspond to a valid position in the file (F2008 9.3.3.4p4 bullet 5, see also Note 9.10). This is to accommodate file structures that use more than one file position for things like the end of record marker (e.g. perhaps they use CR-LF).
(I note that you are also assuming that a default CHARACTER occupies one file storage unit - that is also processor dependent.)
program stream
implicit none
character(len=1) :: text
integer(kind=4), dimension(100) :: array
integer(kind=4) :: status = 0, i
open( &
unit=11, &
file='out.txt', &
form='formatted', &
access='stream', &
action='readwrite', &
status='replace' )
array = [(i, i = 1,100)] ! Populate vector from 1 to 100
write (unit=11, fmt='(10i4)') array ! Write array to file
rewind 11
do
read (unit=11, fmt='(a1)', iostat=status, advance='no') text
if (is_iostat_eor(status)) then
write (*, fmt="()")
cycle
else if (status /= 0) then
exit
end if
write (*,fmt='(a1)', advance='no') text ! write results to screen to see what is in each position
end do
close(unit=11)
end program stream
Upvotes: 2