Help us understand the problem. What is going on with this article?

Fortran ファイル入力での行読み飛ばし

シーケンシャル・ファイルからデータを読み込む時、不要な行を読み飛ばすのには、空の 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
cure_honey
Fortran でおk。 https://twitter.com/Fortran2008
http://oomorigohan.tumblr.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away