Adding information to file by ID in column in Fortran - join

I am trying to combine multiple files in Fortran.
The files all have one column in common ("einst")
The main file has over 100.000 lines but the other files contain extra info about some of the IDs in the main file.
I want to merge the smaller files into the large file and keep all the IDs from the large file that did not get extra information from the smaller files.
I previously asked a similar question...
Can I join two files by a matching column in fortran?
..... And had great success but with that code BUT, IDs that are NOT in BOTH data files will not appear in the new merged data file.
Here is my unsuccessful attempt:
program sameining2
implicit none
integer,parameter :: k15 = selected_int_kind(15)
integer, parameter :: noeinst=25 !LARGE FILE
integer, parameter :: nosaed_k=3 !SMALL FILE
integer, parameter :: nosaed_1=3 !SMALL FILE
integer, parameter :: nosaed_2=3 !SMALL FILE
integer, parameter :: nosaed_3=3 !SMALL FILE
!COLUMNS IN LARGE FILE
integer(kind=k15), dimension(1:noeinst) :: einstg
integer, dimension(1:noeinst) :: bu, faeding, forgun
!COLUMNS IN SMALL FILE, firstlastkvigur
integer(kind=k15), dimension(1:nosaed_k) :: einst_k
integer, dimension(1:nosaed_k) :: frjot_k, fyrstasaed_k, &
fjoldisaed_k, sidastasaed_k
!COLUMNS IN SMALL FILE, firstlastmjalt1
integer(kind=k15), dimension(1:nosaed_1) :: einst_1
integer, dimension(1:nosaed_1) :: frjot_1, fyrstasaed_1, &
fjoldisaed_1, sidastasaed_1
!COLUMNS IN SMALL FILE, firstlastmjalt2
integer(kind=k15), dimension(1:nosaed_2) :: einst_2
integer, dimension(1:nosaed_2) :: frjot_2, fyrstasaed_2, &
fjoldisaed_2, sidastasaed_2
!COLUMNS IN SMALL FILE, firstlastmjalt3
integer(kind=k15), dimension(1:nosaed_3) :: einst_3
integer, dimension(1:nosaed_3) :: frjot_3, fyrstasaed_3, &
fjoldisaed_3, sidastasaed_3
integer :: i, j, k, m, n
!------------------------------------
!READING THE LARGE FILE
open (unit=11, file="gripalistis.txt", status="old")
do k = 1, noeinst
read (11,1011) einstg(k), bu(k), faeding(k), forgun(k)
1011 format (i15,1x,i7,1x,i8,1x,i8)
enddo
close (11, status="keep")
!READING THE SMALL FILE
open (unit=20000, file="firstlastkvigur.txt", status="old")
do i = 1, nosaed_k
read (20000,1017) einst_k(i), frjot_k(i), fyrstasaed_k(i), sidastasaed_k(i), &
fjoldisaed_k(i)
enddo
!READING THE SMALL FILE
open (unit=30000, file="firstlastmjalt1.txt", status="old")
do j = 1, nosaed_1
read (30000,1017) einst_1(j), frjot_1(j), fyrstasaed_1(j), sidastasaed_1(j), &
fjoldisaed_1(j)
enddo
!READING THE SMALL FILE
open (unit=40000, file="firstlastmjalt2.txt", status="old")
do m = 1, nosaed_2
read (40000,1017) einst_2(m), frjot_2(m), fyrstasaed_2(m), sidastasaed_2(m), &
fjoldisaed_2(m)
enddo
!READING THE SMALL FILE
open (unit=50000, file="firstlastmjalt3.txt", status="old")
do n = 1, nosaed_3
read (50000,1017) einst_3(n), frjot_3(n), fyrstasaed_3(n), sidastasaed_3(n), &
fjoldisaed_3(n)
enddo
close (20000, status="keep")
close (30000, status="keep")
close (40000, status="keep")
close (50000, status="keep")
!------------------------------------
open (unit=80, file=pth//"alldata.txt", status="new")
!This program does not work and it only starts with the first two files...
! HERE I AM TRYING TO TELL THE PROGRAM TO WRITE ALL INFORMATION NEW AND OLD IF
!THE IDs match, AND ELSE IT SHOULD JUST PRINT THE INFO FROM THE LARGE FILE
!------------------------------------
do i = no, nosaed_k
do k = 1, noeinst
if (einst_kf(i) == einstg(k) ) then
write (80,1018) einstg(k), bu(k), faeding(k), forgun(k)
frjot_k(i), fyrstasaed_k(i), sidastasaed_k(i), fjoldisaed_k(i)
else
write (80,1018) einstg(k), bu(k), faeding(k), forgun(k)
endif
1018 format (i15,1x,i7,1x,i8,1x,i8,1x &
i3,1x,i8,1x,i8,1x,i2,1x &
i8,1x,i8,1x,i2 )
enddo
enddo
close (80, status="keep")
1017 format (i15,1x,i3,1x,i8,1x,i8,1x,i2)
endprogram sameining2
But what happens is that the do loop compares the first ID in the first file to all the ID in the second file and just writes it over and over again and I get a very large wrong file.
I am not skilled enough to write do loops that compare the IDs from both files, writes information from both files if there is a match but if there is not a match in the small file it only writes information that was already in the large file.
My main goal is actually to try to combine 4 smaller files into the large data file and end up with the same amount of IDs as the original large file but all the extra information in the small files has merged to matching IDs.
But the code above only attempts to merge two files.
Edit:
I have added types for all the 5 files and below there are previews of the files. I have not edited the do loop I tried to make.
My final goal is a file with this information:
einstg(k), bu(k), faeding(k), forgun(k),
frjot_k(i), fyrstasaed_k(i), sidastasaed_k(i), fjoldisaed_k(i),
frjot_1(j), fyrstasaed_1(j), sidastasaed_1(j), fjoldisaed_1(j),
frjot_2(m), fyrstasaed_2(m), sidastasaed_2(m), fjoldisaed_2(m),
frjot_3(n), fyrstasaed_3(n), sidastasaed_3(n), fjoldisaed_3(n)
Help with my problem would be very much appreciated!
Edit:
Preview of the files:
gripalisti.txt
200716619210513 1661921 20070309 20101012
200716619210514 1661921 20070317 20120919
200716619210515 1661921 20070425 20110208
200716619210521 1661921 20070730 20121211
200716619210522 1661921 20070812 20131125
200716619210525 1661921 20071114 20141121
200716619210526 1661921 20071123 20140205
200716619210530 1661921 20071223 20101129
200716619510154 1661951 20070201 20131115
200716619510156 1661951 20070203 20090709
200716619510157 1661951 20070203 20110715
200716619510158 1661951 20070215 20100611
200716619510159 1661951 20070322 20181116
200716619510160 1661951 20070525 20150807
200716619510161 1661951 20070526 20090417
200816385110263 1638511 20080514 20170629
200816385110267 1638511 20080806 20170127
200816385110268 1638511 20080827 20170725
200816385110276 1638511 20081112 20121120
200816386010531 1638881 20080207 20130314
200816386010532 1637551 20080213 20131107
200816386010533 1638601 20080213 20120224
200816386010543 1638601 20080305 20100901
200816386010544 1638601 20080306 20101015
200816386010546 1638921 20080311 20160113
firstlastkvigur.txt
200716619210513 32 20090309 20091218 6
200816386010531 60 20091013 20091013 1
200816386010546 89 20091215 20100113 3
firstlastmjalt1.txt
200716619210521 32 20111218 20111218 1
200716619210525 162 20101207 20101207 1
200816386010533 60 20100928 20101019 2
firstlastmjalt2.txt
200716619510154 10 20130612 20130724 5
200716619510159 10 20120612 20120715 1
200816386010533 10 20110612 20150722 1
firstlastmjalt3.txt
200716619210513 34 20111218 20111218 7
200716619210526 34 20091215 20100113 2
200716619510158 54 20100928 20101019 2

I think the code you want is this:
module m
implicit none
integer, parameter :: k15 = selected_int_kind(15)
type :: EinstData
integer(k15) :: einst
integer :: bu
integer :: faeding
integer :: forgun
end type
type :: SaedData
integer(k15) :: einst
integer :: frjot
integer :: fyrstasaed
integer :: sidastasaed
integer :: fjoldisaed
end type
contains
end module
program p
use m
implicit none
character(14), parameter :: einst_filename = 'gripalisti.txt'
integer, parameter :: einst_size = 25
character(19), parameter :: saed_filenames(3) = [ 'firstlastkvigur.txt', &
& 'firstlastmjalt1.txt', &
& 'firstlastmjalt2.txt' ]
integer, parameter :: saed_sizes(3) = [3, 3, 3]
type(EinstData) :: einst(1:einst_size)
type(SaedData) :: saed
type(SaedData) :: einst_saed(1:einst_size)
logical :: einst_has_saed(1:einst_size)
character(23) :: einst_format = '(i15,1x,i7,1x,i8,1x,i8)'
character(25) :: saed_format = '(1x,i3,1x,i8,1x,i8,1x,i2)'
integer :: i,j,k
! Read the main file.
open(unit=11, file=einst_filename, status='old')
do i=1,einst_size
read(11,*) einst(i)%einst, &
& einst(i)%bu, &
& einst(i)%faeding, &
& einst(i)%forgun
enddo
close(11)
! Read each small file in turn.
einst_has_saed = .false.
do i=1,3
open(unit=11, file=saed_filenames(i), status='old')
do j=1,saed_sizes(j)
read(11,*) saed%einst, &
& saed%frjot, &
& saed%fyrstasaed, &
& saed%sidastasaed, &
& saed%fjoldisaed
! Find the matching line from the main file.
! If found, set einst_saed(k) and set einst_has_saed(k) to true.
do k=1,einst_size
if (einst(k)%einst==saed%einst) then
einst_saed(k) = saed
einst_has_saed(k) = .true.
endif
enddo
enddo
close(11)
enddo
! Write the output file.
open(unit=11, file='alldata.txt', status='new')
do i=1,einst_size
write(11, einst_format, advance='no') einst(i)%einst, &
& einst(i)%bu, &
& einst(i)%faeding, &
& einst(i)%forgun
if (einst_has_saed(i)) then
write(11, saed_format, advance='no') einst_saed(i)%frjot, &
& einst_saed(i)%fyrstasaed, &
& einst_saed(i)%sidastasaed, &
& einst_saed(i)%fjoldisaed
endif
write(11, *)
enddo
close(11)
end program
which produces alldata.txt:
200716619210513 1661921 20070309 20101012
200716619210514 1661921 20070317 20120919
200716619210515 1661921 20070425 20110208
200716619210521 1661921 20070730 20121211 32 20111218 20111218 1
200716619210522 1661921 20070812 20131125
200716619210525 1661921 20071114 20141121 162 20101207 20101207 1
200716619210526 1661921 20071123 20140205
200716619210530 1661921 20071223 20101129
200716619510154 1661951 20070201 20131115
200716619510156 1661951 20070203 20090709
200716619510157 1661951 20070203 20110715
200716619510158 1661951 20070215 20100611
200716619510159 1661951 20070322 20181116
200716619510160 1661951 20070525 20150807
200716619510161 1661951 20070526 20090417
200816385110263 1638511 20080514 20170629
200816385110267 1638511 20080806 20170127
200816385110268 1638511 20080827 20170725
200816385110276 1638511 20081112 20121120
200816386010531 1638881 20080207 20130314
200816386010532 1637551 20080213 20131107
200816386010533 1638601 20080213 20120224 60 20100928 20101019 2
200816386010543 1638601 20080305 20100901
200816386010544 1638601 20080306 20101015
200816386010546 1638921 20080311 20160113

Related

Is there any way to transform "blkparse output file" to "blktrace raw binary file"?

I'm trying to replay blocktrace record file through fio (using --read_iolog option).
However, I only have the output file of blkparse (not output of blktrace or binary dump), which is not accpeted by fio.
blkparse output file (which I have) example:
8,0 1 1 0.000000000 30628 A WS 67045376 + 2047 <- (8,2) 65994752
Is there any way to transform "blkparse output file" to "raw blktrace (merged) binary file"?
= In the below situation, I only have B file without A file, how can I get C file?
blkparse --dump-binary=C --output=B --input=A
Thanks

How to read 2-byte float in Erlang?

Seems there are a lot of half float questions in other languages, but could not find one for Erlang.
So, I have a 2-byte float as part of a longer binary pattern input. I tried to use pattern matching like <<AFloat:16/float>> and got warning/error in compiler, while using 32/float produced no warning.
Question is: What workaround is there in Erlang to convert the 2-byte binary into float?
I saw the other elaborate bit processing answer to "reading from binary file in Erlang", and do not know if it is required in this case.
* Thanks for the answers below. I shall try them out later *
-- two sets of sample input: EF401C3FEA3F, 1242C341C341
It looks like Erlang does not support float widths other than 32 and 64 (at least currently), but I can't seem to find any documentation that says this explicitly.
Update: I checked the implementation of the bit syntax, and it definitely only handles 32 and 64 bit floats. This should really be better documented.
Update again: added to documentation upstream now.
Final update: Just saw your note about hex input. If you solve that as a first step, transforming the hex string H to a binary B with the actual data bytes, you can use the following to repack the data as 32-bit floats (a simple transformation), and then extract those the normal way:
Floats = [F || <<F:32/float>> <- [<<S:1,(E+(127-15)):8,(M bsl 13):23>> || <<S:1,E:5,M:10>> <- B]]
There is no support for 16 bit floats. If you want collect and works on float coming from another system (via a file for example) then you can easily convert this float to the representation used in your VM.
First read the file and extract the float16 as a 2 bytes binary, and call this conversion function:
-module (float16).
-export([conv_16_to_vm/1]).
% conv_16_to_vm(binary) with binary is a 16 bit float representation
conv_16_to_vm(<<S:1,E:5,M:10>>)->
conv(S,E,M).
conv(_,0,0) -> 0.0;
conv(_,31,_) -> {error,nan_or_qnan_or_infinity};
% Sign management
conv(1,E,M) -> -conv(0,E,M);
% sub normal floats
conv(0,0,M) -> M/(1 bsl 24);
% normal floats
conv(0,E,M) when E < 25 -> (1024 + M)/(1 bsl (25-E));
conv(0,25,M) -> (1024 + M);
conv(0,E,M) -> (1024 + M)*(1 bsl (E-25)).
I used the definition provided by Wikipedia and you can test it:
1> c(float16).
{ok,float16}
2> float16:conv_16_to_vm(<<0,1>>). % 0 00000 0000000001
5.960464477539063e-8
3> float16:conv_16_to_vm(<<3,255>>). % 0 00011 1111111111
6.097555160522461e-5
4> float16:conv_16_to_vm(<<4,0>>). % 0 00100 0000000000
6.103515625e-5
5> float16:conv_16_to_vm(<<123,255>>). % 0 11110 1111111111
65504
6> float16:conv_16_to_vm(<<60,0>>). % 0 01111 0000000000
1.0
7> float16:conv_16_to_vm(<<60,1>>). % 0 01111 0000000001
1.0009765625
8> float16:conv_16_to_vm(<<59,255>>). % 0 01110 1111111111
0.99951171875
8> float16:conv_16_to_vm(<<53,85>>). % 0 01101 0101010101
0.333251953125
As you should expect, the traditional problem or "rounding" is much more visible.

Erlang compare two binary file line by line

I tried to compare difference from two binary file, but get confused to compare line by line when reading the file. Like read the first line in the both files, then compare, then read second line of both files to compare
read(B1,B2) ->
{ok, Binary} = file:read_file(B1),
X=[binary_to_list(Bin)||Bin<-binary:split(Binary, [<<"\n">>], [global])],
{ok, Data} = file:read_file(B2),
Y=[binary_to_list(Bin)||Bin<-binary:split(Data, [<<"\n">>], [global])],
compare(X,Y).
compare(X,Y)->
C3=lists:subtract(F1, F2),
io:format("~p~p",[C3,length(C3)]).
You can use lists:zip() to join the two lists into a single list of {Xn, Yn} pairs (check that their lengths are the same first), then lists:foreach() on the result.
You should give more details about what you want to do and what you have tried so far.
I join an example of code that performs the comparison, prints the different lines with the line number, prints the remaining lines if one file is longer.
I do not transform binaries to list, it is unnecessary and inefficient.
-module (comp).
-export ([compare/2]).
compare(F1,F2) ->
{ok,B1} = file:read_file(F1),
{ok,B2} = file:read_file(F2),
io:format("compare file 1: ~s to file 2 ~s~n",[F1,F2]),
compare( binary:split(B1, [<<"\n">>], [global]),
binary:split(B2, [<<"\n">>], [global]),
1).
compare([],[],_) ->
io:format("the 2 files have the same length~n"),
done();
compare([],L,N) ->
io:format("----> file 2 is longer:\n"),
print(L,N);
compare(L,[],N) ->
io:format("----> file 1 is longer:\n"),
print(L,N);
compare([X|T1],[X|T2],N) -> compare(T1,T2,N+1);
compare([X1|T1],[X2|T2],N) ->
io:format("at line ~p,~nfile 1 is: ~s~nfile 2 is: ~s~n",[N,X1,X2]),
compare(T1,T2,N+1).
print([],_) -> done();
print([X|T],N) ->
io:format("line ~p: ~s~n",[N,X]),
print(T,N+1).
done() -> io:format("end of comparison~n").
a small test:
1> c(comp).
{ok,comp}
2> comp:compare("../doc/sample.txt","../doc/sample_mod.txt").
compare file 1: ../doc/sample.txt to file 2 ../doc/sample_mod.txt
at line 9,
file 1 is: Here's an example:
file 2 is: Here's an example (modified):
at line 22,
file 1 is: ```
file 2 is: ```
----> file 2 is longer:
line 23:
line 24: Extra text...
line 25:
end of comparison
ok
3> comp:compare("../doc/sample.txt","../doc/sample.txt").
compare file 1: ../doc/sample.txt to file 2 ../doc/sample.txt
the 2 files have the same length
end of comparison
ok
4>

Read 16 bit little-endian, then parse as a bitstring in erlang

I've inherited a binary file format with the following specification:
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
0:| Status bit | ------ 15 - bit unsigned integer -----------
1:| Status bit | ---- uint:10 ---- | ---- uint:5 ----
Bit matching in Erlang is awesome. So I'd love to do something like this:
<<StatBit1:1, ValA:15/unsigned>> = <<2#1000000000101010:16>>.
<<StatBit2:1, ValB:10/unsigned, ValC:5/unsigned>> = <<2#0000001010100111:16>>.
The problem is that the file I need to process is saved in 8-bit-little-endian
convention. So the very first 8-bits of the file in the example above would be
00101010 then 1000000 e.t.c.
{ok, S} = file:open("datafile", [read, binary, raw]).
{ok, <<Byte1:8, Byte2:8, Byte3:8, Byte4:8>>} = file:read(S,4).
io:format(
" ~8.2.0B | ~8.2.0B | ~8.2.0B | ~8.2.0B ~n ",
[Byte1, Byte2, Byte3, Byte4]).
# 00101010 | 1000000 | 10100111 | 00000010
# ok
So I resort to reading and swapping the bytes:
<<StatBit1:1, ValA:15/unsigned>> = <<Byte2:8, Byte1:8>>.
<<StatBit2:1, ValB:10/unsigned, ValC:5/unsigned>> = <<Byte4:8, Byte3:8>>.
Alternatively I can read 16 bit little-endian and then "parse" it:
{ok, S} = file:open("datafile", [read, binary, raw]).
{ok, <<DW1:16/little, DW2:16/little>>} = file:read(S,4).
<<StatBit1:1, ValA:15/unsigned>> = <<DW1:16>>.
<<StatBit2:1, ValB:10/unsigned, ValC:5/unsigned>> = <<DW2:16>>.
Both solutions make me equally frustrated. I still suspect that there is a nice way of
dealing with that type of situations. Is there?
I'd first look into changing the application generating these files to write the data in network (big-endian) order. If that's not possible, then you're stuck with byte swapping like you're already doing. You could wrap the swapping into a function to keep it out of your decoding logic:
byteswap16(F) ->
case file:read(F, 2) of
{ok, <<B1:8,B2:8>>} -> {ok, <<B2:8,B1:8>>};
Else -> Else
end.
Alternatively, perhaps you could preprocess the file. You mentioned in your comment that the files are huge, so maybe this isn't practical for your case, but if each file fits comfortably in memory you could use file:read_file/1 to read the whole file and then preprocess the contents using a binary comprehension:
byteswap16(Filename) ->
{ok,Bin} = file:read_file(Filename),
<< <<B2:8,B1:8>> || <<B1:8,B2:8>> <= Bin >>.
Both these solutions assume the entire file is written in 16-bit little endian format.
As an explanation of why the binary syntax (as it is) can't solve your problem, consider that the bits in your file really is in order 7, ...0, F, E, ...8. The status bit is in F, but if you say "the next field is 15 bits long, and is a little-endian unsigned integer", you'll get bits 7,...0,F,E,...9 (the next 15 bits) which will then be interpreted as little-endian. You can't express the fact that you'd like to skip bit F and use E-8 instead, and then go back and pick up bit F for the status. If you could byte swap the file first, e.g. with "dd if=infile of=outfile conv=swab", you'd make your life a whole lot easier.
Did you try something like:
[edit] make some correction, but I can't test this on my tab.
decode(<<A:8, 1:1, B:7>>) -> {status1, B*256+A};
decode(<<A:3, C:5, 0:1, B:7>>) -> {status2, B*8+A, C}.

Read numbers following a keyword into an array in Fortran 90 from a text file

I have many text files of this format
....
<snip>
'FOP' 0.19 1 24 1 25 7 8 /
'FOP' 0.18 1 24 1 25 9 11 /
/
TURX
560231
300244
70029
200250
645257
800191
900333
600334
770291
300335
220287
110262 /
SUBTRACT
'TURX' 'TURY'/
</snip>
......
where the portions I snipped off contain other various data in various formats. The file format is inconsistent (machine generated), the only thing one is assured of is the keyword TURX which may appear more than once. If it appears alone on one line, then the next few lines will contain numbers that I need to fetch into an array. The last number will have a space then a forward slash (/). I can then use this array in other operations afterwards.
How do I "search" or parse a file of unknown format in fortran, and how do I get a loop to fetch the rest of the data, please? I am really new to this and I HAVE to use fortran. Thanks.
Fortran 95 / 2003 have a lot of string and file handling features that make this easier.
For example, this code fragment to process a file of unknown length:
use iso_fortran_env
character (len=100) :: line
integer :: ReadCode
ReadLoop: do
read (75, '(A)', iostat=ReadCode ) line
if ( ReadCode /= 0 ) then
if ( ReadCode == iostat_end ) then
exit ReadLoop
else
write ( *, '( / "Error reading file: ", I0 )' ) ReadCode
stop
end if
end if
! code to process the line ....
end do ReadLoop
Then the "process the line" code can contain several sections depending on a logical variable "Have_TURX". If Have_TRUX is false you are "seeking" ... test whether the line contains "TURX". You could use a plain "==" if TURX is always at the start of the string, or for more generality you could use the intrinsic function "index" to test whether the string "line" contains TURX.
Once the program is in the mode Have_TRUX is true, then you use "internal I/O" to read the numeric value from the string. Since the integers have varying lengths and are left-justified, the easiest way is to use "list-directed I/O": combining these:
read (line, *) integer_variable
Then you could use the intrinsic function "index" again to test whether the string also contains a slash, in which case you change Have_TRUX to false and end reading mode.
If you need to put the numbers into an array, it might be necessary to read the file twice, or to backspace the file, because you will have to allocate the array, and you can't do that until you know the size of the array. Or you could pop the numbers into a linked list, then when you hit the slash allocate the array and fill it from the linked list. Or if there is a known maximum number of values you could use a temporary array, then transfer the numbers to an allocatable output array. This is assuming that you want the output argument of the subroutine be an allocatable array of the correct length, and the it returns one group of numbers per call:
integer, dimension (:), allocatable, intent (out) :: numbers
allocate (numbers (1: HowMany) )
P.S. There is a brief summary of the language features at http://en.wikipedia.org/wiki/Fortran_95_language_features and the gfortran manual has a summary of the intrinsic procedures, from which you can see what built in functions are available for string handling.
I'll give you a nudge in the right direction so that you can finish your project.
Some basics:
Do/While as you'll need some sort of loop
structure to loop through the file
and then over the numbers. There's
no for loop in Fortran, so use this
type.
Read
to read the strings.
To start you need something like this:
program readlines
implicit none
character (len=30) :: rdline
integer,dimension(1000) :: array
! This sets up a character array with 30 positions and an integer array with 1000
!
open(18,file='fileread.txt')
do
read(18,*) rdline
if (trim(rdline).eq.'TURX') exit !loop until the trimmed off portion matches TURX
end do
See this thread for way to turn your strings into integers.
Final edit: Looks like MSB has got most of what I just found out. The iostat argument of the read is the key to it. See this site for a sample program.
Here was my final way around it.
PROGRAM fetchnumbers
implicit none
character (len=50) ::line, numdata
logical ::is_numeric
integer ::I,iost,iost2,counter=0,number
integer, parameter :: long = selected_int_kind(10)
integer, dimension(1000)::numbers !Can the number of numbers be up to 1000?
open(20,file='inputfile.txt') !assuming file is in the same location as program
ReadLoop: do
read(20,*,iostat=iost) line !read data line by line
if (iost .LT. 0) exit !end of file reached before TURX was found
if (len_trim(line)==0) cycle ReadLoop !ignore empty lines
if (index(line, 'TURX').EQ.1) then !prepare to begin capturing
GetNumbers: do
read(20, *,iostat=iost2)numdata !read in the numbers one by one
if (.NOT.is_numeric(numdata)) exit !no more numbers to read
if (iost2 .LT. 0) exit !end of file reached while fetching numbers
read (numdata,*) number !read string value into a number
counter = counter + 1
Storeloop: do I =1,counter
if (I<counter) cycle StoreLoop
numbers(counter)=number !storing data into array
end do StoreLoop
end do GetNumbers
end if
end do ReadLoop
write(*,*) "Numbers are:"
do I=1,counter
write(*,'(I14)') numbers(I)
end do
END PROGRAM fetchnumbers
FUNCTION is_numeric(string)
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: string
LOGICAL :: is_numeric
REAL :: x
INTEGER :: e
is_numeric = .FALSE.
READ(string,*,IOSTAT=e) x
IF (e == 0) is_numeric = .TRUE.
END FUNCTION is_numeric

Resources