Operations on external files
Last updated on 2026-02-21 | Edit this page
Overview
Questions
- How do I open and close files for input and output?
- How do I handle any errors that might occur during I/O?
Objectives
- Learn how to open and close files for input and output using a unit number.
- Be able to read and write to an open file and handle errors that might arise.
- Move around an open file using
readto move forwards andbackspace()andrewind()to move back.
Operations on external files
Writing data to, or reading data from, an external file is an essential part of a useful application.
Writing a file
File handles, or unit numbers are obtained using
open(), and are used to direct the output of
write() to the relevant file.
FORTRAN
integer :: myunit
open(newunit = myunit, file = 'filename.dat', form = 'formatted', &
action = 'write', status = 'new')
write(unit = myunit, *) data1 ! write data first record
write(unit = myunit, *) data2 ! second record ... and so on
close(unit = myunit, status = 'keep')
To read back the same data, we might use:
FORTRAN
open(newunit = myunit, file = 'filename.dat', form = 'formatted', &
action = "read", status = "old")
read(unit = myunit, *) data1
read(unit = myunit, *) data2
close (unit = myunit, status = 'keep')
Unit numbers
A valid unit number can be assigned by using the newunit
option to open() – this has been available since Fortran
2008. There is no need to choose your own (and it can be error-prone to
do so).
Note that a given file can only be connected to one unit number at any given time.
open()
The arguments seen above include:
-
file: literal string or character variable or expression with the name of the file in the file system; -
form:formattedorunformatted; -
action:read,writeorreadwrite. An error may occur if inappropriate actions are performed; -
status: one ofold,new,replace,scratch, orunknown.
A file with status old is expected to exist, while an
attempt to create a new file when one already exists with
the same name will result in an error. If replace is
specified, any existing file will be overwritten by a new file. If
scratch is specified, a temporary file is created which
will be deleted when close() is executed (or at the end of
the program). The system will automatically choose a name for a scratch
file if no file argument is present. The default status is
unknown, which means the status is system dependent.
Formally, only the unit number is mandatory (and must appear first), but there is no reason not to provide as much information as possible.
inquire()
The inquire statement offers a way to obtain information
on the current state of either unit numbers or files. There are a large
number of optional arguments. One common usage is to check whether a
file exists:
Internal files
In some situations, it may be convenient to use a formatted read to
generate a new string in memory (in the same way as sprintf
in C). Fortran uses a so-called internal file, which is usually
a character string. E.g.,
Here buffer takes the place of the input unit. This can
be used, e.g., to create format strings at run time.
Recovery from errors
Operations on external files can be error-prone. While there is no formal exception mechanism in Fortran, some ability to recover is available.
Consider the following schematic example:
FORTRAN
subroutine read_my_file_format(myunit, ..., ierr)
integer, intent(in) :: myunit
integer, intent(out) :: ierr ! error code
character (len = 256) :: msg
read (myunit, ..., err = 999, iomsg = msg) ...
! Everything was ok
ierr = 0
return
999 continue
ierr = -1
print *, "Error reading file: ", trim(msg)
return
end subroutine real_my_file_format
We assume the relevant file has been opened successfully, and is
connected to unit number myunit. If an error occurs at the
point of the read statement, the err argument directs
control to be transferred to the statement will label 999.
In this case the system should provide a meaningful message describing
the error.
If the read is successful, the routine completes at the first return
statement with intent out ierr = 0.
Error handling for open() and close()
Both open and close statements provide
optional arguments for error handling, illustrated schematically here
with open():
FORTRAN
integer :: ierr
character (len = 128) :: msg
open( newunit = myunit, ..., err = 900, iostat = ierr, iomsg = msg)
-
err: is a label in the same scope to which control is transferred on error; -
iostat: an integer variable which is zero on success but positive if an error has occurred; -
iomsg: if an error occurs, a system-dependent message will be assigned tomsg.
If neither err nor iostat arguments are
present, then an error may result in immediate termination of the
program.
The variable msg should be a scalar character variable;
the message will be truncated or padded appropriately.
Error handling for read() and write()
Error handling facilities for read() and
write() are similar, and are illustrated here:
-
end: label in same scope to which control is transferred on end-of-file; -
err: label in same scope to which control is transferred on any other error; the label may be the same asend; -
iostat: the integer error code is negative if end-of-record or end-of-file, or positive if another error (e.g., bad format conversion) or zero on success; -
iomsg: should return a useful message on error.
The two negative iostat cases can be distinguished via
calls to the intrinsic functions
stop statement
If one really can’t continue, then execution can be terminated
immediately via the stop statement. This has an optional
message string argument.
In general one should try to recover by returning control to the
caller, so stop is a last resort.
Moving around an open file
It is sometimes useful to be able to reposition oneself in an open
file so that a given record can be read (or written) more than once.
This can be done using backspace() with the relevant unit
number. Formally
This steps back one record.
It is also possible to reposition to the beginning of the file, again
with the relevant connected unit number using rewind().
Exercise (20 minutes)
Writing a simple image
Portable bit map (PBM, PGM, PPM) is a very simple image format which can be expressed as an ASCII file. See the description at Wikipedia.
In the template program1.f90, we establish
a two-dimensional logical array of a fixed size, and we want to write
out a file that can be viewed in “P1” format (file extension
.pbm ) by an image viewer.
The data is initialised with a suitable pattern to check that the image is correct (it is the right way up and is not a mirror). A little care is required in the rows and columns (look closely at the example).
Provide a module with the subroutine write_pbm() with
three arguments as in the template program. Note the template program
expects a module solution_module.
Additional exercises: repeat for integer data (to “P2” format
.pgm) and floating point data (to “P3” format
.ppm).
You can check any image you produce by either downloading it to your
machine with scp or rsync, or you can view it
directly on ARCHER2 by logging in with X11 forwarding enabled, running
module load imagemagick and then
display test49.pbm.
A solution to this problem appears in the later episode on interfaces.
You should be able to produce an output PBM that looks like the example shown below.

- Writing data to, or reading data from, an external file is an essential part of a useful application.
- Unit numbers are integers which are used as handles to open files.
- Errors from I/O can be handled with labels and by examining the returned message.