AGP (an unusual name) asked:
>I have been programming in F90 and F95 on a win98 machine
>and I have been given the task of extracting data from
>a binary file into ASCII. I consider myself a good programmer
>but this is a bit above my head. The binary file is described
>as "data as a binary integer array (PC byte-ordered) with
With luck you are reading the file on a PC or other little-endian machine,
otherwise you'll need to swap the bytes around after reading them in.
Painful but not too difficult - I recommend using ISHFT myself, though
others like to use (ugh) EQUIVALENCE or (shudder) TRANSFER. YMMV.
You don't mention the size of each data element; perhaps it is 32-bit which
matches default integer on most machines.
>10800 columns (e-w) by 6000 or 4800 rows (n-s)....the data
I don't quite understand what you mean by this - I'll assume you mean that
the data is stored in columns - viz the first column followed by 4799 (or
5999) others.
I'll also assume there is no other data in the file.
>are also unsigned integers".
Unsigned integers can be emulated with double precision, because a double
precision mantissa has lots more bits than an ordinary integer. You do need
to do some conversion though - see below.
>How would I use FORTRAN to extract the binary into an ASCII text file.
Although it is not possible to do this portably in Fortran 90/95, it is
possible with most compilers without using compiler-specific extensions.
The trick which usually works is to use unformatted direct-access files.
Here is an example of how it could be done.
Again, I've just typed this in without testing it, so there may be typos...
program byte_extract
integer,parameter :: column_length = 10800
integer column(column_length),recnum
character input
inquire(size=recl) column ! Discover correct RECL value
open(88,file="input.data",form="unformatted",recl=recl)
open(77,file="output.txt",form="formatted",recl=column_length*10+1)
do recnum=1,6000
read(88,rec=recnum,err=666) column
if (recnum==4801 .and. all(column==0)) then
print *,'Column 4801 is all zeroes - probably no more data'
! ask whether to continue. advance='no' usually works for prompts...
do
write(*,'(a)',advance='no') 'Continue (Y or N)'
read(*,'(a)') input
if (input=='N' or input=='n') goto 666
if (input=='Y' or input=='y') exit
print *,"Please type Y or N - I don't know what '",input,'" means.'
end do
end if
call print(77,column)
end do
666 close(88)
print *,recnum-1,"columns printed"
contains
subroutine print(unit,data)
!
! This will print each "column" as a single row in the output.
! Numbers will be separated by blanks.
!
integer unit,data(:),i
double precision tmp
character*10 string
do i=1,size(data)
!
! if you need to do byte-swapping, here is a good place.
! something like
! data(i) = ior(ior(ior(ishft(iand(data(i),255),24),
! ishft(iand(data(i),ishft(255,8)),8)),
! ishft(iand(data(i),ishft(255,16)),-8)),
! ishft(iand(data(i),ishft(255,24)),-24))
! ! Turns bytes 1234 into 4321
!
if (data(i)>=0) then
write(unit,'(I10)',advance='no') data(i)
else
! Use double precision to do longer-than-32-bits integer arithmetic
! We'll assume twos complement representation
tmp = iand(data(i),huge(0)) ! huge(0) = all bits set except sign bit
! Now add 2**31, first as huge(0)==2**31-1, then add 1.
tmp = tmp + huge(0)
tmp = tmp + 1
! Write it to a string so we can get rid of the '.'
write(string,'(F11.0)') tmp
write(unit,'(A)',advance='no') string(:10)
end if
end do
write(unit,'()') ! Terminate the record
end subroutine
end
Cheers,
--
...........................Malcolm Cohen, NAG Ltd., Oxford, U.K.
([log in to unmask])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|