シーケンシャル・ファイルからデータを読み込む時、不要な行を読み飛ばすのには、空の READ 文で十分です。(かつそのほうが速いはずです)
ファイル入力読み飛ばし
Fortran のプログラム質問サイトなどを見ていますと、ファイルからデータを読み込む時、不要な行を読み飛ばすのにダミー変数への入力などをしている例が多く見受けられます。しかし、実は読み込み変数を何も書かない空っぽの READ 文だけで次の行に飛んでくれます。
書式付きの場合は、ダミー読み込みのための書式変換が要らず改行を探すだけになるため負荷が軽くなります。
書式なしの場合は(普通は)行頭と行末にレコード長が埋め込まれているので次の行まで飛ばして行けます。なお行末にもレコード長が埋め込まれているのは BACKSPACE 文で逆戻りするためで、順方向にも逆方向にも同じ感じで行をスキップして進んで行けるようになっています。
例
以下で書式なしの場合について実際の例を見てみます。
ここではまずウォーミングアップに 100 要素の実数配列を 1 行に一気に書き出します。ファイルを rewind 文で巻き戻した後、一気に 100 個のデータを読み込みます。またファイルを巻き戻して、1 行につき 1 個のデータを書き出してゆきます。
次に BACKSPACE 文で 1 行づつ 50 行ばかり逆戻りしてゆきます。そこからまたファイルの最後まで行を読み飛ばしながら行数を数えてゆきます。
ファイル末まで来たのは iostat 調べますが、EOF (end of file) を表す数が iso_fortran_env の中に iostat_end として定義されるようになったので (f08) これを用いてみました。(伝統的に Fortran では EOF を表す数は -1 になっているので、わざわざ無理しなくてもいいんですが。忘れてましたが is_iostat_end() という関数もありました。f08)
program IOtest
use, intrinsic :: iso_fortran_env, only : iostat_end
implicit none
real :: x(100), y(100)
integer :: i, k, io, ipos
forall(i = 1:100) x(i) = real(i)
write(9) x
rewind(9)
read(9) y
rewind(9)
rewind(9)
do i = 1, 100
write(9) y(i)
end do
do i = 1, 50
backspace(9)
end do
k = 0
do
read(9, iostat = io)
if (io == iostat_end) exit
k = k + 1
end do
print *, 'number of data', k
end program IOtest
実行結果
100 行のデータを書き込んだ後、backspace 文 50 回で 50 行逆戻りしたので、そこから end_of_file まで行を読み飛ばしてゆくと、当然データ数は 50 行分になります。
number of data 50
おまけ
書式なしフォーマットの内部。
規格で規定されているわけではないけれども、一般に Fortran の書式なしのシーケンシャル・ファイル(順並びファイル)は、各行に対応するレコードの前後に、レコード長が書き込まれています。(最近では 4 バイト整数値で)
前後に書き込まれているのは、空の READ 文や BACKSPACE 文で順方向・逆方向に素早くデータを読み飛ばしてヘッドを動かすためだと思われます。
READ - BACKSPACE と順方向と逆方向で命令が対称になっていないのは歴史的な理由でご愛嬌w
program IOtest2
implicit none
integer :: i, k, ix(3)
forall(i = 1:3) ix(i) = i
write(9) ix
do i = 1, 3
write(9) ix(i)
end do
close(9)
open(9, access = 'stream')
do
read(9, end = 99) k
print *, k
end do
99 continue
end program IOtest2
実行結果 intel fortran 調べ
4バイト整数の要素3の配列と、4バイト整数が3個書き出されているので、以下の様な4バイト整数値がファイルに書き込まれている。
12byte 1, 2, 3 12byte
4byte 1 4byte
4byte 2 4byte
4byte 3 4byte
12
1
2
3
12
4
1
4
4
2
4
4
3
4