Files

In order to read data from or write data to file, a handle must be created with the open statement first. By default, file access is Fortran is record based.

Open

A unit number must be given to the open statement, usually, an integer ≥ 10. The unit number is used like a file handle in other programming languages.

integer :: rc

open (action='read', file='data.txt', iostat=rc, unit=20)
if (rc /= 0) stop 'Error: open failed'
close (20)

The specifier iostat returns the status of the operation. The Fortran 2008 standard introduced the newunit specifier that simply returns an unused unit number.

integer :: fu
integer :: rc

open (action='read', file='data.txt', iostat=rc, newunit=fu)
if (rc /= 0) stop 'Error: open failed'
close (fu)

Using specifier newunit instead of unit, we do not have to keep track of distinctive unit numbers that have to be defined in advance.

open ([unit=]u, list)
Specifier Values Default Function
access direct, sequential, stream sequential Access mode (optional).
action read, readwrite, write readwrite Kind of file access (optional).
asynchronous no, yes no Enable asynchronous I/O (optional).
blank null, zero null Interpretation of blanks (optional).
decimal comma, point point Decimal edit mode (optional).
delim apostrophe, none, quote none Delimiter for character constants (optional).
encoding default, utf-8 default Encoding form for file (optional).
err label Label to jump to on error (optional, deprecated).
file character(len=*) File name or * (optional).
form formatted, unformatted depends on access Format type (optional).
iostat integer I/O status, 0 if open was successful (optional).
newunit integer Returns unused I/O unit (optional, unless status='scratch').
pad no, yes yes Record padding (optional).
position append, asis, rewind asis File positioning (optional).
recl integer Record length (optional).
status old, new, scratch, replace, unknown unknown File status at open (optional).
unit integer I/O unit of the file (mandatory, unless newunit=u or status='scratch').

Close

File handles must be closed with the close statement. If opened with write access, a file can be deleted after closing by setting the specifier status='delete':

integer :: fu, rc

open (action='write', file='data.txt', iostat=rc, newunit=fu, status='old')
if (rc /= 0) stop 'Error: opening file failed'
close (fu, status='delete')
close ([unit=]u, list)
Specifier Values Default Function
err label Label to jump to on error (optional, deprecated).
iostat integer I/O status (optional).
status keep, delete keep Delete file on close if opened with access='write' or access='readwrite' (optional).
unit integer I/O unit of the file (mandatory).

Inquire

The intrinsic inquire statement returns status information of a given file, file unit, or output list:

The statement can be executed before, during, or after the file is connected to a unit.

The inquire statement returns, for example, whether or not a file exists:

logical :: file_exists

inquire (exist=file_exists, file='data.txt')

if (.not. file_exists) &
    print '(a)', 'Error: File not found'

Since Fortran 2003, we can also query the size of a file:

integer :: n
logical :: file_exists

inquire (exist=file_exists, file='data.txt', size=n)

if (file_exists) &
    print '(a, i0, a)', 'Size: ', n, ' bytes'

Fortran compilers may provide additional non-standard specifiers.

inquire (file=name[, list])
inquire ([unit=]u[, list])
inquire (iolength=iolength) output-items
Specifier Values Default Function
access SEQUENTIAL, STREAM, DIRECT, UNDEFINED Returns how file is connected (optional).
action READ, WRITE, READWRITE, UNDEFINED Allowed I/O operations for file (optional).
asynchronous YES, NO, UNKNOWN Returns whether asynchronous I/O is in effect (optional).
blank NULL, ZERO Returns whether blanks in numeric fields are to be interpreted as null fields or zeros (optional).
decimal COMMA, POINT, UNDEFINED Returns which decimal editing mode is in effect for a file connection (optional).
delim APOSTROPHE, QUOTE, NONE, UNDEFINED Delimiter in list-directed files (optional).
direct YES, NO, UNKNOWN Returns whether file is connected for direct access (optional).
encoding UTF-8, UNDEFINED, UNKNOWN Returns type of encoding of the file (optional).
err label Label to jump to on error (optional, deprecated).
exist logical Set to .true. if file exists, else .false. (optional).
file character(len=*) Name of the file for inquiry (mandatory if unit is not set).
form FORMATTED, UNFORMATTED, UNDEFINED Returns whether file is connected for formatted or unformatted data transfer (optional).
formatted YES, NO, UNKNOWN Returns whether file is connected for formatted data transfer (optional).
id integer If the data transfer specified by id is complete, then pending is set to .false. and inquire waits for the specified data transfer. If the data transfer specified by id is not complete, then pending is set to .true., without waiting. The previously pending data transfer remains pending after the execution of the inquire statement (optional).
iostat integer I/O status, 0 if open was successful (optional).
name character(len=*) undefined Returns file name, if available (optional).
named logical Set to .true. if file has file name, else .false. (optional).
nextrec integer 1 Number of the next record (optional).
number integer I/O unit of the file, if connected (optional).
opened logical Set to .true. if file/unit is connected to a file/unit, else .false. (optional).
pad YES, NO Returns whether blank padding was specified for the file (optional).
pending logical Returns previously pending asynchronous data transfers are complete. If there is no id specifier and all data transfer operations for the specified unit are complete, then the variable specified in pending is assigned the value .false. and the inquire statement performs wait operations for all previously pending data transfers for the specified unit (optional).
pos integer Returns file position for a file connected for stream access in file storage units, usually in bytes (optional).
position REWIND, ASIS, APPEND, UNDEFINED Returns position of the file (optional).
read YES, NO, UNKNOWN Returns whether the file can be read (optional).
readwrite YES, NO, UNKNOWN Returns whether the file can be both read and written to (optional).
recl integer Maximum record length allowed for the file (optional).
round UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED The attribute specifies how decimal numbers are converted to an internal representation, from a character representation and vice versa during formatted input and output (optional). The rounding modes have the following functions:
  • In the UP rounding mode the value from the conversion is the smallest value that is greater than or equal to the original value.
  • In the DOWN rounding mode the value from the conversion is the greatest value that is smaller than or equal to the original value.
  • In the ZERO rounding mode the value from the conversion is the closest value to the original value, and not greater in magnitude.
  • In the NEAREST rounding mode the value from the conversion is the closer of the two nearest representable values. If both values are equally close then the even value will be chosen. In IEEE rounding conversions, NEAREST corresponds to the ieee_nearest rounding mode as specified by the IEEE standard.
  • In the COMPATIBLE rounding mode the value from the conversion is the closest of the two nearest representable values, or the value further away from zero if halfway between.
  • In the PROCESSOR_DEFINED rounding mode the value from the conversion is processor dependent and may correspond to the other modes.
sequential YES, NO, UNKNOWN Returns whether the file is connected for sequential access (optional).
sign PLUS, SUPPRESS, PROCESSOR_DEFINED, UNDEFINED Returns the sign mode in effect for a connection for formatted I/O, i. e., whether plus signs are shown or suppressed (optional).
size integer -1 Size of the file in file storage units, usually in bytes (optional).
stream YES, NO, UNKNOWN Returns whether the file is connected for stream access (optional).
unformatted YES, NO, UNKNOWN Returns whether the file is connected for unformatted data transfer (optional).
unit integer I/O unit of the file (mandatory if file is not set).
write YES, NO, UNKNOWN Returns whether the file can be written to (optional).

Backspace

The backspace statement positions the specified file to just before the preceding record.

backspace ([unit=]u, list)
Specifier Values Default Function
err label Label to jump to on error (optional, deprecated).
iostat integer I/O status (optional).
unit integer I/O unit of the file (mandatory).

Rewind

The rewind statement positions the file associated with the specified unit to its initial point.

rewind ([unit=]u, list)
Specifier Values Default Function
err label Label to jump to on error (optional, deprecated).
iostat integer I/O status (optional).
unit integer I/O unit of the file (mandatory).

Reading Files

Using the read statement, the contents of a single line can be stored in a primitive or derived type variable. In order to read muliple lines sequentially, we have to call read inside a do loop.

A text file data.txt with an arbitrary number of lines is given:

1,"Mediterranean Avenue",60
2,"Baltic Avenue",60
3,"Oriental Avenue",100
4,"Vermont Avenue",100
5,"Connecticut Avenue",120
6,"St. Charles Place",140

The following example can be used to read and output the file contents:

! reader.f90
program main
    use, intrinsic :: iso_fortran_env, only: error_unit
    implicit none

    character(len=*), parameter :: FILE_NAME = 'data.txt'
    character(len=100) :: street
    integer            :: i, fu, price, rc

    open (action='read', file=FILE_NAME, iostat=rc, newunit=fu)

    if (rc /= 0) then
        write (error_unit, '(3a, i0)') 'Reading file "', FILE_NAME, '" failed: ', rc
        stop
    end if

    do
        read (fu, *, iostat=rc) i, street, price                    ! Read line from file.
        if (rc /= 0) exit                                           ! Exit on error.
        print '(i1, 3a, i3)', i, ': ', trim(street), ', $', price   ! Output values.
    end do

    close (fu)
end program main

Reading CSV Files

In order to read files containing comma-separated values (CSV), a derived type representing the data structure is declared. Assume a CSV file data.txt with the following contents:

Vostok 1,1961,Yuri Gagarin
Vostok 2,1961,Gherman Titov
Vostok 3,1962,Andriyan Nikolayev
Vostok 4,1962,Pavel Popovich
Vostok 5,1963,Valery Bykovsky
Vostok 6,1963,Valentina Tereshkova

A proper type declaration for this data set may be:

type :: mission_type
    character(len=8)  :: name
    integer           :: year
    character(len=20) :: pilot
end type mission_type

type(mission_type) :: missions(6)
integer            :: fu, rc

Open the CSV file and iterate over the file contents to read all lines into the array:

open (action='read', file='data.txt', iostat=rc, newunit=fu)

if (rc /= 0) stop

do i = 1, 6
    read (fu, *, iostat=rc) missions(i)
    if (rc /= 0) exit
end do

close (fu)

The result is an array of mission type variables, whose values can be easily accessed by index and attribute:

print *, missions(1)%pilot

The file length (number of lines) has to be known in advance. Otherwise, re-allocate the array on each iteration using the intrinsic Fortran routine move_alloc(), or use a linked list instead.

Reading Entire Files

An entire file can be read at once into an allocatable character variable if the file size is determined with the inquire statement beforehand and the file is opened in stream mode, for instance:

! entire.f90
program main
    implicit none
    character(len=:), allocatable :: buffer
    integer                       :: fu, n, rc

    ! Open file in stream mode.
    open (access  = 'stream', &
          action  = 'read', &
          file    = 'data.txt', &
          form    = 'unformatted', &
          iostat  = rc, &
          newunit = fu)
    if (rc /= 0) stop 'Error: opening file failed'

    ! Get file size and allocate buffer string.
    inquire (fu, size=n)
    allocate (character(len=n) :: buffer)

    ! Read file into buffer.
    read (fu, iostat=rc) buffer
    close (fu)

    print '(a)', buffer
end program main

Writing Files

Writing to files does not differ much from reading from files. First, the file has to be opened for writing, using either action='write' or action='readwrite' in the open statement. Then, we can append data with the write statement. The example below writes the string Hello, World! to file data.txt.

! writer.f90
program main
    implicit none

    character(len=*), parameter :: FILE_NAME = 'data.txt'
    integer :: fu
    integer :: rc

    open (action='write', file=FILE_NAME, status='replace', iostat=rc, newunit=fu)

    if (rc /= 0) then
        print '(3a)', 'Error: opening file "', FILE_NAME, '" failed'
        stop
    end if

    ! Write string to file.
    write (fu, '(a)') 'Hello, World!'

    close (fu)
end program main

In case the file data.txt already exists, it will be replaced.

Libraries