Fortran Programming Guide

Accessing Files From Within Fortran Programs

Data is transferred between the program and devices or files through a Fortran logical unit. Logical units are identified in an I/O statement by a logical unit number, a nonnegative integer from 0 to the maximum 4-byte integer value (2,147,483,647).

The character * can appear as a logical unit identifier. The asterisk stands for standard input file when it appears in a READ statement; it stands for standard output file when it appears in a WRITE or PRINT statement.

A Fortran logical unit can be associated with a specific, named file through the OPEN statement. Also, certain "preconnected" units are automatically associated with specific files at the start of program execution.

Accessing Named Files

The OPEN statement's FILE= specifier establishes the association of a logical unit to a named, physical file at runtime. This file can be pre-existing or created by the program. See the Sun FORTRAN 77 Language Reference Manual for a full discussion of the OPEN statement.

The FILE= specifier on an OPEN statement may specify a simple file name (FILE='myfile.out') or a file name preceded by an absolute or relative directory path (FILE='../Amber/Qproj/myfile.out'). Also, the specifier may be a character constant, variable, or character expression.

Library routines can be used to bring command-line arguments and environment variables into the program as character variables for use as file names in OPEN statements. (See man page entries for getarg(3F) and getenv(3F) for details; these and other useful library routines are also described in the Fortran Library Reference).

The following example (GetFilNam.f) shows one way to construct an absolute path file name from a typed-in name. The program uses the library routines GETENV, LNBLNK, and GETCWD to return the value of the $HOME environment variable, find the last non-blank in the string, and determine the current working directory:


      CHARACTER F*128, FN*128, FULLNAME*128
      PRINT*, 'ENTER FILE NAME:'
      READ *, F 
      FN = FULLNAME( F ) 
      PRINT *, 'PATH IS: ',FN
      END 

      CHARACTER*128 FUNCTION FULLNAME( NAME ) 
      CHARACTER NAME*(*), PREFIX*128
C          This assumes C shell.
C           Leave absolute path names unchanged. 
C           If name starts with '~/', replace tilde with home 
C           directory; otherwise prefix relative path name with 
C           path to current directory. 
      IF ( NAME(1:1) .EQ. '/' ) THEN 
            FULLNAME = NAME 
      ELSE IF ( NAME(1:2) .EQ. '~/' ) THEN 
            CALL GETENV( 'HOME', PREFIX ) 
            FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 
&                         NAME(2:LNBLNK(NAME)) 
      ELSE 
            CALL GETCWD( PREFIX ) 
            FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 
&                         '/' // NAME(:LNBLNK(NAME)) 
      ENDIF 
      RETURN 
      END

Compiling and running GetFilNam.f results in:


demo% pwd
/home/users/auser/subdir
demo% f77 -silent -o getfil GetFilNam.f
demo% getfil
anyfile
/home/users/auser/subdir/anyfile
demo%

Opening Files Without a Name

The OPEN statement need not specify a name; the runtime system supplies a file name according to several conventions.

Opened as Scratch

Specifying STATUS='SCRATCH' in the OPEN statement opens a file with a name of the form tmp.FAAAxnnnnn, where nnnnn is replaced by the current process ID, AAA is a string of three characters, and x is a letter; the AAA and x make the file name unique. This file is deleted upon termination of the program or execution of a CLOSE statement, unless (with f77) STATUS='KEEP' is specified in the CLOSE statement.

Already Open

If the file has already been opened by the program, you can use a subsequent OPEN statement to change some of the file's characteristics; for example, BLANK and FORM. In this case, you would specify only the file's logical unit number and the parameters to change.

Preconnected Units

Three unit numbers are automatically associated with specific standard I/O files at the start of program execution. These preconnected units are standard input, standard output, and standard error:

Typically, standard input receives input from the workstation keyboard; standard output and standard error display output on the workstation screen.

In all other cases where a logical unit number but no FILE= name is specified on an OPEN statement, a file is opened with a name of the form fort.n, where n is the logical unit number.

Opening Files Without an OPEN Statement

Use of the OPEN statement is optional in those cases where default conventions can be assumed. If the first operation on a logical unit is an I/O statement other than OPEN or INQUIRE, the file fort.n is referenced, where n is the logical unit number (except for 0, 5, and 6, which have special meaning).

These files need not exist before program execution. If the first operation on the file is not an OPEN or INQUIRE statement, they are created.

Example: The WRITE in the following code creates the file fort.25 if it is the first input/output operation on that unit:


demo% cat TestUnit.f
      IU=25
      WRITE( IU, '(I4)' ) IU 
      END 
demo% 

The preceding program opens the file fort.25 and writes a single formatted record onto that file:


demo% f77 -silent -o testunit TestUnit.f
demo% testunit
demo% cat fort.25
  25
demo%

Passing File Names to Programs

The file system does not have any automatic facility to associate a logical unit number in a Fortran program with a physical file.

However, there are several satisfactory ways to communicate file names to a Fortran program.

Via Runtime Arguments and GETARG

The library routine getarg(3F) can be used to read the command-line arguments at runtime into a character variable. The argument is interpreted as a file name and used in the OPEN statement FILE= specifier:


demo% cat testarg.f
         CHARACTER outfile*40
C  Get first arg as output file name for unit 51
         CALL getarg(1,outfile)
         OPEN(51,FILE=outfile)
         WRITE(51,*) 'Writing to file: ', outfile
         END
demo% f77 -silent -o tstarg testarg.f
demo% tstarg AnyFileName
demo% cat AnyFileName
 Writing to file: AnyFileName
demo%

Via Environment Variables and GETENV

Similarly, the library routine getenv(3F) can be used to read the value of any environment variable at runtime into a character variable that in turn is interpreted as a file name:


demo% cat testenv.f
         CHARACTER outfile*40
C  Get $OUTFILE as output file name for unit 51
         CALL getenv('OUTFILE',outfile)
         OPEN(51,FILE=outfile)
         WRITE(51,*) 'Writing to file: ', outfile
         END
demo% f77 -silent -o tstenv testenv.f
demo% setenv OUTFILE EnvFileName
demo% tstenv
demo% cat EnvFileName
 Writing to file: EnvFileName
demo%

When using getarg or getenv, care should be taken regarding leading or trailing blanks. (FORTRAN 77 programs can use the library function LNBLNK; Fortran 90 programs can use the intrinsic function TRIM.) Additional flexibility to accept relative path names can be programmed along the lines of the FULLNAME function in the example at the beginning of this chapter.

f77: Logical Unit Preattachment Using IOINIT

The library routine IOINIT can also be used with f77 to attach logical units to specific files at runtime. IOINIT looks in the environment for names of a user-specified form and then opens the corresponding logical unit for sequential formatted I/O. Names must be of the general form PREFIXnn, where the particular PREFIX is specified in the call to IOINIT, and nn is the logical unit to be opened. Unit numbers less than 10 must include the leading 0. See the Sun Fortran Library Reference, and the IOINIT(3F) man page. (The IOINIT facility is not implemented for f90.)

Example: Associate physical files test.inp and test.out in the current directory to logical units 1 and 2:

First, set the environment variables.

With ksh or sh:


demo$ TST01=ini1.inp
demo$ TST02=ini1.out
demo$ export TST01 TST02

With csh:


demo% setenv TST01 ini1.inp
demo% setenv TST02 ini1.out


demo% cat ini1.f 
      CHARACTER PRFX*8 
      LOGICAL CCTL, BZRO, APND, VRBOSE 
      DATA CCTL, BZRO, APND, PRFX, VRBOSE 
&                   /.TRUE.,.FALSE.,.FALSE., 'TST',.FALSE. / 
      CALL IOINIT( CCTL, BZRO, APND, PRFX, VRBOSE ) 
      READ(1, *) I, B, N 
      WRITE(2, *) I, B, N 
      END 
demo%

The program ini1.f reads 1 and writes 2:

With environment variables and ioinit, ini1.f reads ini1.inp and writes to ini1.out:


demo% cat ini1.inp
 12 3.14159012 6
demo% f77 -silent -o tstinit ini1.f
demo% tstinit
demo% cat ini1.out
  12    3.14159  6
demo%

IOINIT is adequate for most programs as written. However, it is written in Fortran specifically to serve as an example for similar user-supplied routines. Retrieve a copy from the following file, a part of the FORTRAN 77 package installation: /opt/SUNWspro/SC5.0/src/ioinit.f

Command-Line I/O Redirection and Piping

Another way to associate a physical file with a program's logical unit number is by redirecting or piping the preconnected standard I/O files. Redirection or piping occurs on the runtime execution command.

In this way, a program that reads standard input (unit 5) and writes to standard output (unit 6) or standard error (unit 0) can, by redirection (using <, >, >>, >&, |, |&, 2>, 2>&1 on the command line), read or write to any other named file.

This is shown in the following table:

Table 2-1 csh/sh/ksh Redirection and Piping on the Command Line

Action 

Using C Shell 

Using Bourne or Korn Shell 

Standard input --read from mydata 

myprog < mydata myprog < mydata

Standard output --write (overwrite) myoutput 

myprog > myoutput myprog > myoutput

Standard output -- write/append to myoutput 

myprog >> myoutput myprog >> myoutput

Redirect standard error to a file 

myprog >& errorfile myprog 2> errorfile

Pipe standard output to input of another program 

myprog1 | myprog2 myprog1 | myprog2

Pipe standard error and output to another program 

myprog1 |& myprog2 myprog1 2>&1 | myprog2

See the csh, ksh,and sh man pages for details on redirection and piping on the command line.

f77: VAX / VMS Logical File Names

If you are porting from VMS FORTRAN to FORTRAN 77, the VMS-style logical file names in the INCLUDE statement are mapped to UNIX path names. The environment variable LOGICALNAMEMAPPING defines the mapping between the logical names and the UNIX path name. If the environment variable LOGICALNAMEMAPPING is set and the -vax, -xl or -xld compiler options are used, the compiler interprets VMS logical file names on the INCLUDE statement.

The compiler sets the environment variable to a string with the following syntax:


      "lname1=path1; lname2=path2;  " 

Each lname is a logical name, and each path is the path name of a directory (without a trailing /). All blanks are ignored when parsing this string. Any trailing /list or /nolist is stripped from the file name in the INCLUDE statement. Logical names in a file name are delimited by the first colon in the VMS file name. The compiler converts file names of the form:


      
lname1:file

to:


      
path1/file 

Uppercase and lowercase are significant in logical names. If a logical name is encountered on the INCLUDE statement that was not specified by LOGICALNAMEMAPPING, the file name is used unchanged.