STREAM I/O questions

STREAM I/O questions

Post by John » Sat, 27 Jun 2009 17:13:31


I have a number of Fortran codes (mostly graphics-related or special
! text-based utilities) that need stream I/O. C was the dominant
stream-I/O
! based language; so "When in Rome, do as the Romans do." seemed like
a
! good idea; so when available (as in gfortran/g95) I used the "C-
like"
! extensions:
!
! ftell, fseek, fputc, fgetc, fget, fput
! As described at
! http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gfortran/FTELL.html
!
! or called C from Fortran and make look-alikes for the routines.
There
! were a few bumps along the way (in some programming environments (in
! the past?) mixing C and Fortran I/O (heck, just mixing C and
Fortran)
! was fraught with peril.
!
! As g95(1) and other compilers have now implemented the F2003 stream
! I/O interface, I thought I could now make standard-based routines
with
! the same functionality (just using Fortran 2003; not the
ISO_C_BINDING
! interface to call C).
!
! So if I open a NAMED file with ACCESS="STREAM" it is quite straight-
forward.
! I can use reads and writes with POS= to do what FSEEK(3F) does; I
can use
! INQUIRE(UNIT=nn,POS=itell)
! itell=itell-1
! to replace FTELL(3F); and (for NAMED files that I opened) a simple
! WRITE(nn,'(a)') char --> FPUTC(3F)
! READ(nn,'(a)') char --> FGETC(3F)
!
! But I can't figure out a standard method of making the files pre-
assigned
! to standard input and standard output (and stderr and other pre-
assigned
! files too, I suppose) use stream I/O.
!
!
! Here is a simple demo. program I have to kludge to write to standard
! output, for example:
!-------------------------------------------------------------------------------
! read entire file into memory as a stream and write it in reverse
byte order
program rev_file

!
! access computing environment
USE ISO_FORTRAN_ENV, ONLY : ERROR_UNIT,INPUT_UNIT,OUTPUT_UNIT
implicit none
character(len=1024) :: filein
character(len=1024) :: fileout
character(len=1),allocatable :: text(:)
integer :: ios
integer :: iputunit=16

if(command_argument_count() < 1 .or. command_argument_count() .gt.
2 )then
call stderr('usage: rev inputfile [outputfile]')
stop
elseif(command_argument_count() .eq. 2)then
! get output filename
call get_command_argument(2,fileout)
! open named file in stream mode positioned to append
open (unit=iputunit, &
& file=fileout(:len_trim(fileout)), &
& access='stream')
iputunit=16
else
iputunit=6
endif

! call with each token from the command line
call GET_COMMAND_ARGUMENT(1, filein)
! allocate character array and copy file into it
call juslurp(filein,text)
if(command_argument_count() .eq. 1)then
! KLUDGE
! write file reversed to stdout
write(*,'(2000000000000000a:)',advance='no')text(size(text):
1:-1)
else
! write file reversed to a non-preassigned file
write(iputunit)text(size(text):1:-1)
endif

! release memory
deallocate(text)
close(16, iostat=ios)
!-------------------------------------------------------------------------------
contains
! allocate text() and read file filename into it
subroutine juslurp(filename,text)
!-------------------------------------------------------------------------------
! read an entire file into memory as a stream
! comment: never casually read an entire file into memory
 
 
 

STREAM I/O questions

Post by Arjen Mark » Sat, 27 Jun 2009 17:54:49

n 26 jun, 10:13, John < XXXX@XXXXX.COM > wrote:
> !> > ! or called C from Fortran and make look-alikes for the routines.> > There> > ! were a few bumps along the way (in some programming environments (in> > ! the past?) mixing C and Fortran I/O heck, just mixing C an>
> Fortran>
> ! was fraught with peril>
> >
> ! As g95(1) and other compilers have now implemented the F2003 strea>
> ! I/O interface, I thought I could now make standard-based routine>
> wit>
> ! the same functionality (just using Fortran 2003; not th>
> ISO_C_BINDIN>
> ! interface to call C)>
> >
> ! So if I open a NAMED file with ACCESS="STREAM" it is quite straight>
> forward>
> ! I can use reads and writes with POS= to do what FSEEK(3F) does; >
> can us>
> ! NQUIRE(UNIT=nn,POS=itel>)
> ! tell=itel>-1
> ! to replace FTELL(3F); and (for NAMED files that I opened) a sim>le
> ! RITE(nn,'(a)') c>ar -> FPUT>(3F)
> ! EAD(nn,'(a)') >har --> FG>TC(3>)
> !
> ! But I can't figure out a standard method of making the fil>s pre-
> a>signed
> ! to standard input and standard output (and stderr and oth>r pre-
> a>signed
> ! files too, I suppose) use stre>m I/>.
>>!
> !
> ! Here is a simple demo. program I have to kludge to write to s>andard
> ! output, for e>ample:
> !------------------------------------------------------------------------>-----
> ! read entire file into memory as a stream and write it in>reverse
> by>e order
> program >ev>file> >
> !
> ! access computing env>ronment
> USE ISO_FORTRAN_ENV, ONLY : ERROR_UNIT,INPUT_UNIT,OUT>UT_UNIT
> impli>it none
> haracter(len=1024) >: filein
> haracter(len=1024) >: fileout
> haracter(len=1),allocatable>:: text(:)
> n>eger :: ios
> nteger :> i>utunit=16
>
> f(command_a<gument_count() < 1 .or. command_argumen>_count() .>t.
> 2 )then
> all stderr('usage: rev inputfil> [outputfi>e]')
> top
> lseif(command_argument_>ount() .eq. 2)then
> gt;! get output filename
> call get_co>mand_argument(2,fileout)
> ! open named file in stre>m mode positioned to append
> gt;open (unit=iputunit,
> gt;& file=fileout(:len_>rim(fileout)), >
> gt;& access='stream>)
> gt;ip>tunit=16
> lse
> iputunit=6
> n>if
>
> call with each token from t>e command line
> all GET_COMMAND_ARGUMENT(1, fi>ein)
> allocate characte> array and copy file into it
> all jusl>rp(filein,text>
> f(command_argument_count() .e>. 1)then
> ! KLUDGE
> ! write file reversed to stdou>
> > write(*,>(2000000000000000a:)',advance='no')text(size(text):
> lse
> ! write file re>ersed to a>no>-preassigned file
>>write(iputunit)>ext(size(text):1:-1)
> >endif
>
> release memory
> eallocate(text)
> lose(16, iostat=ios) >> !---------->---------------------------------------------------->--------------
> ontains
> gt; allocate text() and read file filename into it
> ubroutine juslurp(filename,t>xt)
> !----------------------------------------->------------------------------------
> ! ead an entire file into me>ory as a stream
> ! omment: never casually read an entire file>into m>mory if you can
> ! process it per line or in smaller >nits; as>large files
> can
> ! consume unreasonable amounts o> memory. What if someone
> f>eds >> ! in a file
 
 
 

STREAM I/O questions

Post by Arjen Mark » Sat, 27 Jun 2009 19:13:45

n 26 jun, 10:54, Arjen Markus < XXXX@XXXXX.COM > wrote:
> > ! tell=itel>->
> > ! to replace FTELL(3F); and (for NAMED files that I opened) a sim>l>
> > ! RITE(nn,'(a)') c>ar -> FPUT>(>F)
> > ! EAD(nn,'(a)') >har --> FG>T>(3F)> > > ! But I can't figure out a standard method of making the fil>s>pre-
> > a>s>gned
> > ! to standard input and standard output (and stderr and oth>r>pre-
> > a>s>gned
> > ! files too, I suppose) use stre>m>I/O.> > > ! Here is a simple demo. program I have to kludge to write to s>a>dard
> > ! output, for e>a>ple:
> > !-------------------------------------------------------------------------->gt;----
> > ! read entire file into memory as a stream and write it in >e>erse
> > byt> >rder
> > program r>v_>i>e
>> > > ! access computing envi>o>ment
> > USE ISO_FORTRAN_ENV, ONLY : ERROR_UNIT,INPUT_UNIT,OUTP>T>UNIT
> > implic>t>none
> > haracter(len=1024) :> >ilein
> > haracter(len=1024) :> >ileout
> > haracter(len=1),allocatable >:>text(:)
> > nt>g>r :: ios
> > nteger ::>ip>t>nit=16
>
> > f(command_a<gument_count() < 1 .or. command_argument>c>unt() .gt.> > > all stderr('usage: rev inputfile>[>utputfile]>)> > > top
> > lseif(command_argument_c>u>t() .eq. 2)then
> > > >et output filename
> > call get_com>a>d_argument(2,fileout)
> > ! open named file in strea> >ode positioned to append
> > >p>n (unit=iputunit,
> > > > & file=fileout(:len_tri>(>ileout)), &
> > > & ac>e>s='stream')
> >>gt;iputun>t=>6> > > lse
> > iputunit=6
> > ndif> > > call with each token from the >o>mand line
> > all GET_COMMAND_ARGUMENT(1, filei>)> > > allocate character a>r>y and copy file into it
> > all juslurp>f>lein,text)
> > > f(command_argument_count() .eq. 1)>h>n
> > ! KLUDGE
> > ! write file reversed to stdout
> > 1:->)> > > lse
> > ! write file rever>e> to a non->re>s>igned file
> > > >rite(iputunit)text(si>e>text):1:-1)
> > ndif >>> > > release memory
> > eallocate(text)
> > lose(16, iostat=ios)
> > >->------------->->---------------------------------------------------->->------
> > ontains
> > al>o>ate text() and read file filename into it
> > ubroutine juslurp(filename,text)
> > ! ead an entire file into memory >s>a stream
> > ! omment: never casually read an entire file into>m>mory i> >ou can
> > ! process it per line or in smaller units; >s>large fi>e>
> > can
> > ! consume unreasonable amounts of memor>.>What if someone
> > feeds
>>>>! > > in a file ten times bigger than you system memory, for
> > example>(>ven acc>d>ntly?)
> > !
> > ! onsider what happens on machines where more tha> >ne char>c>er is
> > used
> > ! or an end-of-line or a character string>i> used for a> >nternal
> > file
> > ! eperator (usually for "multi-file" files, which were once >>>> common)!
> > !-->->------------------------->->------------------------------------------->->
> > implicit none >>>> ! filename to shlep
> > character(len=*),i>t>nt(in) :: filename
> >>gt;! array to hold file
> > gt;c>aracter(len=1),allocatable,in
 
 
 

STREAM I/O questions

Post by nospa » Sun, 28 Jun 2009 01:27:41


There isn't a guaranteed way. It is compiler- and system-dependent
whether you can do anything like that to standard input and output.
Might work, or might not depending on the compiler.

In principle, it is equally compiler- and system-dependent what you can
do to any file. It is just that standard input/output are more likely
than most other "random" files to have limitations. In general, I advise
against trying to reopen standard input/output.

As Arjen notes, you can use nonadvancing I/O to get some simillar
effects. It won't do all of the same things, but then some of the things
that you can't do with nonadvancing I/O are some of the things likely to
be problematic on standard input and output anyway. For example, it is
reasonably common for standard input/output to be connected to files
that cannot be positioned.


For a general answer to that question, see the INQUIRE statement. It is
fairly common to have a short routine that loops through candidate unit
numbers to find one that is vaid and unused. In practice, I find it
pretty safe today to assume that unit numbers 11 through 99 are valid. I
avoid single-digit unit numbers as they are often used for special
syste-dependent purposes, and 99 is the highest valid unit number on
some compilers (though it seems that most compilers today allow higher
ones).

The f2008 draft (last time I checked) provides a standardized way to get
an unused unit number, with the additional advantage that it gives you
one that is also guaranteed not to be used by anything else in the
future (something you can't otherwise guarantee). That makes it a bit
more like most other current languages, where you don't have to worry
about selecting a number, but just open a file and let the system assign
a suitable "handle". In my opinion, the use of numbers as unit handles
is an undesirable holdover from older days, but the proposed new feature
at least ameliorates the problems.

None of this will tell you, however, things like whether you can
successfully reopen standard input/output. It isn't specific to stream
I/O.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
 
 
 

STREAM I/O questions

Post by glen herrm » Sun, 28 Jun 2009 02:23:39


(snip)

< ! But I can't figure out a standard method of making the
< ! files pre-assigned to standard input and standard output
< ! (and stderr and other pre-assigned files too, I suppose) use
< ! stream I/O.

C has the freopen() function, similar to fopen(), except that
it closes an existing stream and opens the new file on the
same stream. The usual use is for opening a new file as
stdin, stdout, or stderr.

As far as I know, there is no similar operation in Fortran.

-- glen
 
 
 

STREAM I/O questions

Post by John » Sun, 28 Jun 2009 07:49:52


>> As far as I know, there is no similar operation in Fortran. >> >> -- glen

Thanks to everyone for the replies. When I don't have to categorize my
open files
I do use a routine that finds an unused number already( I added it to
http://www.yqcomputer.com/ ); but I often find I need
to maintain a table with a text "tag" so I can scan for related files
(find all input files currently open, ...) so I find I usually use it
for files opened and closed in the same routine ( a help file, a
configuration file, ...). I had seen the f2008
NEWUNIT= put no compiler I tried seem to impliment it yet; I guess
that means if I open all my files that way in the future I don't need
to know the upper limit allowed
(until I hit the limit, I guess). I THINK the f1977 standard
used to say the guaranteed range was 1 to 99; I could
not find anything in the f2008 standard that mentioned any guaranteed
minimum range. freread(3c)
is interesting; somehow I missed that (and I've used
C a decent amount); I guess I am dissapointed that I
still cannot do (in a portable way) what I can do with the common
Fortran stream I/O extensions (ftell,fseek,fputc,fgetc,..). The
example using non-advancing I/O is something I'll keep; but that's
what
I was hoping to become free of ( using non-standard
extensions, calling C routines, not-so-simple uses of
non-advancing I/O and direct access files ) when I
want to make "binary" filters. Everything seems to work just fine
except with pre-connected units; but
I want to do binary streams too often to switch to the newer
ACCESS="STREAM" methods. I could already handle clear text files as
filters with f1977 for the
most part; it's the binary files or times that I want
to hold a text file in memory as a stream that I'd like to do in a
standard way. Thanks again;
John S. Urban
 
 
 

STREAM I/O questions

Post by nospa » Sun, 28 Jun 2009 09:22:16


[about valid unit numbers]

No, it did not. No version of the Fortran standard has ever guaranteed
any particular range. And there were f77 compilers that didn't allow
that large a range, though that was a fairly common choice.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
 
 
 

STREAM I/O questions

Post by jfh » Wed, 01 Jul 2009 07:08:40


A problem with unit numbers that hit me 30 or so years ago was that a
certain commercial graphics package of Fortran subroutines used an
assortment of undocumented unit numbers for its own purposes, and I
had various problems if I tried to write to or read from one of those
units. The source code was not available. My workaround was to write a
test program to INQUIRE of each unit number 0-99 whether it was
currently open, before and after each subroutine call from the
package. (I didn't strike a case where a unit was opened and closed
during one package subroutine call.) Later, my university stopped
paying for that package, and PGPLOT became available. I still use
that.

John Harper
 
 
 

STREAM I/O questions

Post by Ron Shepar » Wed, 01 Jul 2009 09:42:02

In article
< XXXX@XXXXX.COM >,



I think a lot of software did this 30 years ago back before
open/close/inquire statements were available using preconnected
units and/or some kind of JCL incantation. Open statements were
available on, for example, some of the DEC compilers and operating
systems before f77, but not on very many machines made by many other
vendors. F77 fixed this, of course, but that would not really be
popular until the mid 80's, and even then often along with the older
version of the compiler that supported only the preconnected units.
Most software libraries I used at least documented which file unit
numbers they used, although some of them kept the filenames
undocumented (or used random character strings that changed from run
to run).

$.02 -Ron Shepard
 
 
 

STREAM I/O questions

Post by glen herrm » Wed, 01 Jul 2009 12:26:22


<> A problem with unit numbers that hit me 30 or so years ago was that a
<> certain commercial graphics package of Fortran subroutines used an
<> assortment of undocumented unit numbers for its own purposes,
(snip)

< I think a lot of software did this 30 years ago back before
< open/close/inquire statements were available using preconnected
< units and/or some kind of JCL incantation.

The DEC compilers would create a file named after the unit,
like FOR001.DAT

For IBM, you needed a JCL DD statement for each unit.
If closed source software used a unit, it would have to
be documented such that the appropriate DD statement would
be supplied. The system cataloged procedures normally
supplied DD statements for 5, (SYSIN), 6 (SYSOUT=A, line printer),
and 7 (SYSOUT=B, card punch). The number of available units
is a sysgen option, likely more on larger machines.

< Open statements were
< available on, for example, some of the DEC compilers and operating
< systems before f77, but not on very many machines made by many other
< vendors. F77 fixed this, of course, but that would not really be
< popular until the mid 80's, and even then often along with the older
< version of the compiler that supported only the preconnected units.

(snip)

-- glen