Writing to or reading from a file is similar to writing onto a terminal screen or reading from a keyboard.
Differences are:
- File must be opened with an OPEN statement, in which the unit number and (optionally) the filename are given
- Subsequent writes (or reads) must refer to a known unit number (used for open)
- File should be closed at the end
File opening and closing
The syntax is:
OPEN([unit=]lunit,file='name' [,options])
CLOSE([unit=]lunit [,options])
For example:
OPEN(10, file='output.dat', status='new')
CLOSE(unit=10)
- The first parameter is the unit number and the keyword
unit=
can be omitted.
-
The unit numbers 0,5 and 6 are predefined.
- 0 is output for standard (system) error messages
- 5 is for standard (user) input
- 6 is for standard (user) output
- These units are opened by default and should not be re-opened nor closed by users
Some options for opening a file:
- status: existence of the file ('old', 'new', 'replace', 'scratch', 'unknown')
- position: offset, where to start writing ('append')
- action: file operation mode ('write','read','readwrite')
- form: text or binary file ('formatted', 'unformatted')
- access: direct or sequential file access ('direct','sequential','stream')
- iostat: error indicator, (output) integer (non zero only upon an error)
- err: the label number to jump upon error
- recl: record length, (input) integer for direct access files only. Be careful, it can be in bytes or words...
The main options for closing a file:
- iostat: error indicator, (output) integer (non zero only upon an error)
- err: the label number to jump upon error
- status: what to do with the file ('keep', 'remove')
Reading and Writing from/to a file
Writing to and reading from a file is done by giving the unit number as a parameter:
WRITE(10,*) str
WRITE(unit=10, fmt=*) str
READ(lu, *) str
READ(unit=lu,fmt=*) str
If the keyword "unit" is used, you also need to use "fmt" for specifying the format. Please not that
fmt is only applicable to formatted files (text files only)
Formatted and unformatted files
- Text or formatted files are human readable and portable (machine independent).
- Binary or unformatted files are machine dependent, not portable. However, they have a much faster access than formatted files.
Therefore they very well suited when you need to store a large amount of data. The numbers stored in
binary files have kept their internal representation (no conversion, no rounding of errors compared to formatted data).
ascii files (formatted)
To prettify outputs and to make it human readable, use format descriptors in connection
with the WRITE statement. Although less often used nowadays, it can also be used with READ to input data at fixed line positions and using predefined field lengths.
Output Formatting
- integer : Iw, Iw.m
For instance:
WRITE(*, '(I5)') J
Real: Fwd, Ew.d, Ew.dEe, 1P, Gwd
For instance:
WRITE(*,'(F7.4)') R
WRITE(*,'(E12.3E4)') R
WRITE(*,'(1P,G20.13)') R
Character: A, Aw
For instance:
WRITE(*,'(A)') C
Logical: Lw
For instance:
WRITE(*,'(L2)') L
In all these expressions:
- w: width of the output field
- d: number of digits to the right of decimal point
- m: minimum number of characters to be used
- e: number of digits in the exponent
- Variables: Integer :: j; REAL :: R ; CHARACTER :: C; LOGICAL :: L
Binary files (unformatted)
Here is an example to write a sequential binary file:
REAL :: rval
CHARACTER(len=60) :: string
OPEN(10, file="foo.dat", form="unformatted")
WRITE(10) rval
WRITE(10) string
CLOSE(10)
You cannot use any FORMAT descriptors. To read:
READ(10) rval
READ(10) string
Stream Input/Output
A binary file write adds extra record delimiters (hidden from programmer) to the beginning and end of recors. In fortran 2003, using access method 'stream'
avoids this and implements a C-programming like approach:
REAL header(20), data(300)
OPEN(10,file="mydata.dat",access='stream')
WRITE(10) header
WRITE(10) data
CLOSE(10)
If you compare the size of the file generated when using access="stream and without", you will see that the second one is smaller in size.
Internal Input/Output
Often it is necessary to filter out data from a given character string or to pack values into a character string. Fortran internal I/O
with READ and WRITE becomes handy (no physical are involved at all).
For instance to extract a number from a given character string:
CHARACTER(LEN=13) :: CL = "Time step# 10"
INTEGER :: ISTEP
READ(CL,fmt='(10X,I3)') ISTEP
Or to write a text and data to a character string:
CHARACTER(LEN=60) :: CL
WRITE(LC, fmt='(A,I0)') 'The number of jobs completed = ', 100
Other Input/output statements
In addition to the statements that transfer data, there are auxiliary input/output statements to manipulate the external medium, or to inquire about or describe the properties of the connection to the external medium.
There are nine input/output statements:
- READ
- WRITE
- PRINT
- OPEN
- CLOSE
- INQUIRE
- BACKSPACE
- ENDFILE
- REWIND
The READ, WRITE, and PRINT statements are data transfer input/output statements.
The OPEN, CLOSE, INQUIRE, BACKSPACE, ENDFILE, and REWIND statements are auxiliary input/output statements.
The BACKSPACE, ENDFILE, and REWIND statements are file positioning input/output statements.
INQUIRE statement
USE INQUIRE statement to find out information about:
- file existence
- file unit open status
- various file attributes (is the file formatted, unformatted, etc.)
INQUIRE(file=filename [,options])
INQUIRE(unit=lun [, options])
where options can be:
IOSTAT
ERR
EXIST
OPENED
NUMBER
NAMED
NAMEDACCESS
SEQUENTIAL
DIRECT
FORM
FORMATTED
UNFORMATED
RECL
NEXTREC
BLANK
For instance to check if a file exists:
LOGICAL :: lexist
INQUIRE(file="myfile.txt", EXIST=lexist)
If myfile.txt
exists, lexist will become .TRUE. and .FALSE. otherwise.
You can also check if a unit is connected:
LOGICAL :: is_opened
INQUIRE(unit=lun, OPENED=is_opened)
is_opened is set to .TRUE. if the logical unit lun is conected i.e. a file is opened with this logical unit number.