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.
- Fortran Statements
- Examples
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 :: file_unit
integer :: rc
open (action='read', file='data.txt', iostat=rc, newunit=file_unit)
if (rc /= 0) stop 'Error: open failed'
close (file_unit)
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 :: file_unit
integer :: rc
open (action='write', file='data.txt', iostat=rc, newunit=file_unit, status='old')
if (rc /= 0) stop 'Error: opening file failed'
close (file_unit, 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:
- Inquire by file, which requires the
file
specifier. - Inquire by unit, which requires the
unit
specifier. - Inquire by output list, which requires the
iolength
specifier.
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 '("Size: ", i0, " bytes")', n
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:
|
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=72) :: street
integer :: i, file_unit, price, rc
open (action='read', file=FILE_NAME, iostat=rc, newunit=file_unit)
if (rc /= 0) then
write (error_unit, '(3a, i0)') 'Reading file "', FILE_NAME, '" failed: ', rc
stop
end if
do
read (file_unit, *, 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 (file_unit)
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 :: file_unit
integer :: 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=file_unit)
if (rc /= 0) stop
do i = 1, 6
read (file_unit, *, iostat=rc) missions(i)
if (rc /= 0) exit
end do
close (file_unit)
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 :: file_unit, n, rc
! Open file in stream mode.
open (access = 'stream', &
action = 'read', &
file = 'data.txt', &
form = 'unformatted', &
iostat = rc, &
newunit = file_unit)
if (rc /= 0) stop 'Error: opening file failed'
! Get file size and allocate buffer string.
inquire (file_unit, size=n)
allocate (character(len=n) :: buffer)
! Read file into buffer.
read (file_unit, iostat=rc) buffer
close (file_unit)
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 :: file_unit
integer :: rc
open (action='write', file=FILE_NAME, iostat=rc, newunit=file_unit, status='replace')
if (rc /= 0) then
print '(3a)', 'Error: opening file "', FILE_NAME, '" failed'
stop
end if
! Write string to file.
write (file_unit, '(a)') 'Hello, World!'
close (file_unit)
end program main
In case the file data.txt
already exists, it will be replaced.
Fortran Libraries
- fortran-csv-module: Fortran 2008 library for reading and writing CSV files
< Strings | [Index] | Namelists > |