2-8 LOGICAL UNITS AND FILES
****************************
(thanks to Timothy Prince for the important comment)
Note that since operating systems treat peripheral devices as
files (see below), this discussion applies not just to files on
disks and tapes, but also to non-file oriented devices.
Logical Unit Numbers
--------------------
A FORTRAN program may read and write several files at the same time
(including the standard input and output), a convenient method to
'label' the files used is to assign small integers to them.
Similar methods are used in other languages, and the labeling
integers are called: LOGICAL UNIT NUMBERS (LUN) or file handles.
The separation of the file interface into two distinct logical
layers (LUN/file-name) makes it possible to perform the association
between the two at run-time, giving an extra flexibility (see below).
FORTRAN I/O is performed to or from a LOGICAL UNIT identified by the
logical unit number (LUN), the LUN is CONNECTED to a file/device
either explicitly with an OPEN statement or implicitly.
LUNs are global entities in a program, a LUN used in one procedure
to open a file, will refer to the same file in other procedures.
Explicit and Implicit OPEN
--------------------------
Using an 'OPEN' statement is not mandatory but is recommended,
otherwise you may work with system defaults that may be non-portable,
or just strange.
Using an OPEN statement is a good programming practice and
makes it possible to create files with optimal characteristics,
and read existing files in the optimal way.
The following standard OPEN keywords are useful:
Keyword Value Comments
------- ------------- ---------------------------------
UNIT A LUN number In the allowed range (see below)
FILE File name May be a constant/variable
STATUS 'OLD' To use an existing file,
'NEW' To create a new file
ACCESS 'SEQUENTIAL'
'DIRECT' Open for direct (random) access
FORM 'FORMATTED' For an ASCII file
'UNFORMATTED' For a binary file
BLANK 'NULL' Ignore blanks
ERR Statement label to jump to if 'open' fails
On an advantage of using the IOSTAT specifier over the ERR specifier
see the chapter on the three I/O methods.
Non-standard keywords can optimize I/O performance, or enable you
to use INDEXED (non-standard!) files.
Redirecting implicitly opened files
-----------------------------------
If you use the 'FILE' keyword in the 'open' statement, you create
a 'connection' between the LUN and the file name. If you don't use
this keyword a default file name is assumed:
System Default file name
------ -----------------
VMS FORTnnn.DAT
UNIX fort.n
These default file names are used to create one more "naming level".
Using an operating system command it is possible to make the program
process another file without having to re-compile it:
System Command syntax Shell
------ ---------------------- -----
VMS define FOR010 new.dat DCL
IRIX set FOR010 = new.dat ????
setenv FOR010 new.dat ????
AIX ln -s new.dat fort.10 ????
This is a common technique, it gives the programmer more flexibility
managing file I/O.
By the way, a more informative term for 'shell' is 'command language
interpreter'.
Preassigned LUNs
----------------
Some LUNs are permanently assigned (PRECONNECTED) to the standard
input and output devices (the keyboard and screen respectively in
an interactive session).
There is a popular (non-standard!) convention for preassigned LUNs
whose origin is not clear, it is probably derived from IBM practice,
not from the FORTRAN 66 standard:
Unit VMS logical C stream Old I/O Interactive Batch mode
no. device name name usage mode usage usage
---- ---------- -------- ----------- ----------- ----------
0 stderr screen log file
5 SYS$INPUT stdin card reader keyboard
6 SYS$OUTPUT stdout line printer screen log file
Using these LUNs explicitly is bad programming. A better way is:
I/O Statement VMS device UNIX dev Interactive VMS Batch
example session job
------------- ---------- --------- ----------- -------------
read(*,...) SYS$INPUT stdin keyboard batch file
write(*,...) SYS$OUTPUT stdout screen log file
Unix-like redirection makes the use of the * specifiers convenient;
failing that, it's hard to get flexibility without relying on the
non-standard numeric values.
Output redirection
------------------
There is no difference between WRITE(6,*) and WRITE(*,*) when you
redirect program output, except on VMS.
VMS redirects output by redefining the logical name SYS$OUTPUT,
there are two ways an ordinary user can do that:
DEFINE/USER_MODE SYS$OUTPUT FILE.OUT (User-mode)
DEFINE SYS$OUTPUT FILE.OUT (Supervisor-mode)
In supervisor mode you will get one file called FILE.OUT containing
the output of both WRITE(6,*) and WRITE(*,*) statements.
In user mode you will get two versions of the file FILE.OUT, the
first version contains the WRITE(*,*) output and the second the
WRITE(6,*) output.
Range of LUNs
-------------
The range of LUNs is limited in FORTRAN to a subset of the positive
integers:
Operating system Minimal LUN Maximal Lun Open by default
---------------- ----------- ----------- ---------------
VMS 0 119 none
Typical UNIX 0 2**31 - 1 0, 5, 6
DEC (and maybe IRIX) compilers use negative LUNs when you don't
explicitly specify a LUN in an I/O statement.
The default DEC unit numbers are:
I/O STATEMENT UNIT
------------- ----
PRINT -1
TYPE -2
ACCEPT -3
READ -4
Negative unit numbers are unavailable to the programmer, so this
"trick" prevents conflicts between I/O statements that use the
default logical unit numbers and those that use explicit logical
unit numbers.
You usually see these negative logical unit numbers only in error
messages, e.g. run-time error messages produced by the Fortran
run-time library for your compiler.
LUN allocation
--------------
Once a LUN was connected to a file, the connection remains in
effect until an explicit CLOSE statement is executed, then the
LUN is 'released' and you can use it again.
That means that you have to keep track of the LUNs you use in
your program, or have some way to ask the system about them.
You can find if you have already used a certain LUN with the
INQUIRE statement:
INTEGER u
LOGICAL log
............................
u = 10
INQUIRE (UNIT=u, OPENED=log)
C ------------------------------------------------------------------
IF (log) THEN
WRITE (*,*) ' Unit ', u, ' is not free '
ELSE
WRITE (*,*) ' Unit ', u, ' is free '
ENDIF
C ------------------------------------------------------------------
Other INQUIRE keywords check if the unit number is valid ('EXIST'),
and supply information on the connected file.
You may call a system routine (non-standard!) to find a 'free'
LUN and allocate it, afterwards you can deallocate the LUN.
LIB$GET_LUN(u) (VMS)
LIB$FREE_LUN(u)
However, you can easily write a PORTABLE such routine in FORTRAN
using the INQUIRE statement.
Reading/Writing from/to peripheral devices
------------------------------------------
Almost, if not all operating-system unified the I/O operations
performed on peripheral devices, so that devices like printers
and serial ports can be used as if they are files.
Some DOS examples (Maybe you'll need sometimes to add a colon
':' to the device name):
copy CON tmp.tmp (copies anything you type to the file tmp.tmp
CON is the name of the "console" device in
this case it's the keyboard. Exit with CTRL/Z,
then a RETURN)
copy tmp.tmp PRN (prints the file tmp.tmp)
copy tmp.tmp COM1 (sends the file tmp.tmp through the COM1
serial port)
type CON (displays on the screen whatever you type,
after you press RETURN. Exit with CTRL/Z
then a RETURN)
Using the peripheral devices from a program is easy, use the
appropriate device as if it was a file, and do an OPEN:
OPEN(UNIT=unitnum, FILE='devname', STATUS='OLD',...)
than just read/write from/to the opened unit.
The examples here used DOS, but PC operating systems made by
a certain company are rather bad, and you may have to use a
routine library supplied with the compiler.
Return to contents page