Skip to content

Commit 158a970

Browse files
committed
Rework file IO section
- remove mention of impure newunit function hack
1 parent e73677a commit 158a970

File tree

1 file changed

+82
-40
lines changed

1 file changed

+82
-40
lines changed

learn/best_practices/file_io.md

+82-40
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,98 @@ title: File Input/Output
44
permalink: /learn/best_practices/file_io
55
---
66

7-
To read from a file:
7+
In Fortran files are managed by unit identifiers. Interaction with the filesystem
8+
mainly happens through the ``open`` and ``inquire`` built-in procedures.
9+
Generally, the workflow is to open a file to a unit identifier, read and/or write
10+
to it and close it again.
811

9-
``` fortran
10-
integer :: u
11-
open(newunit=u, file="log.txt", status="old", action='read')
12-
read(u, *) a, b
13-
close(u)
12+
```fortran
13+
integer :: io
14+
open(newunit=io, file="log.txt")
15+
! ...
16+
close(io)
1417
```
1518

16-
Write to a file as follows:
19+
By default the file will be created if it is not existing already and opened for
20+
both reading and writing. Writing to an existing file will start in the first
21+
record (line) and therefore overwrite the file by default.
1722

18-
``` fortran
19-
integer :: u
20-
open(newunit=u, file="log.txt", status="replace", action='write')
21-
write(u, *) a, b
22-
close(u)
23+
To create a read-only access to a file the ``status`` and ``action`` have to be
24+
specified with
25+
26+
```fortran
27+
integer :: io
28+
open(newunit=io, file="log.txt", status="old", action="read")
29+
read(io, *) a, b
30+
close(io)
31+
```
32+
33+
In case the file is not present a runtime error will occur. To check for the existence
34+
of a file prior to opening it the ``inquire`` function can be used
35+
36+
```fortran
37+
logical :: exists
38+
inquire(file="log.txt", exist=exists)
39+
if (exists) then
40+
! ...
41+
end if
2342
```
2443

25-
It is possible to append to an existing file as follows:
44+
Alternatively, the ``open`` procedure can return an optional *iostat* and *iomsg*:
2645

27-
``` fortran
28-
integer :: u
29-
open(newunit=u, file="log.txt", position="append", status="old")
30-
write(u, *) N, V(N)
31-
close(u)
46+
```fortran
47+
integer :: io, stat
48+
character(len=512) :: msg
49+
open(newunit=io, file="log.txt", status="old", action="read", &
50+
iostat=stat, iomsg=msg)
51+
if (stat /= 0) then
52+
print *, trim(msg)
53+
end if
3254
```
3355

34-
The `newunit` keyword argument to `open` is a Fortran 2008 standard feature. Therefore for
35-
older compilers that do not suport it, just replace `open(newunit=u, ...)` by:
56+
Note that *iomsg* requires a fixed-length character variable with sufficent storage
57+
size to hold the error message.
58+
59+
Similarly, writing to a file happens by using the *status* and *action* keyword.
60+
To create a new file use
3661

37-
``` fortran
38-
open(newunit(u), ...)
62+
```fortran
63+
integer :: io
64+
open(newunit=io, file="log.txt", status="new", action="write")
65+
write(io, *) a, b
66+
close(io)
3967
```
4068

41-
where the `newunit` function is defined by:
42-
43-
``` fortran
44-
integer function newunit(unit) result(n)
45-
! returns lowest i/o unit number not in use
46-
integer, intent(out), optional :: unit
47-
logical :: inuse
48-
integer, parameter :: nmin=10 ! avoid lower numbers which are sometimes reserved
49-
integer, parameter :: nmax=999 ! may be system-dependent
50-
do n = nmin, nmax
51-
inquire(unit=n, opened=inuse)
52-
if (.not. inuse) then
53-
if (present(unit)) unit=n
54-
return
55-
end if
56-
end do
57-
error stop 'newunit ERROR: available unit not found.'
58-
end function
69+
Alternatively, ``status="replace"`` can be used to overwrite an existing file,
70+
it is highly recommended to first check for the existence of a file before deciding
71+
on the *status* to use.
72+
To append to an output file the *position* keyword can be specified explicitly with
73+
74+
```fortran
75+
integer :: io
76+
open(newunit=io, file="log.txt", position="append", &
77+
& status="old", action="write")
78+
write(io, *) size(v)
79+
write(io, *) v(:)
80+
close(io)
5981
```
82+
83+
To reset the position in a file the built-in procedures ``rewind`` and ``backspace``
84+
can be used. ``rewind`` will reset to the first record (line), while ``backspace`` will
85+
return to the previous record (line).
86+
87+
Finally, to delete a file the file has to be opened and can be deleted after closing
88+
with
89+
90+
```fortran
91+
logical :: exists
92+
integer :: io, stat
93+
inquire(file="log.txt", exist=exists)
94+
if (exists) then
95+
open(file="log.txt", newunit=io, iostat=stat)
96+
if (stat == 0) close(io, status="delete", iostat=stat)
97+
end if
98+
```
99+
100+
A useful IO feature are scratch files, which can be opened with ``status="scratch"``.
101+
They are automatically deleted after closing the unit identifier.

0 commit comments

Comments
 (0)