Fortran プログラミングガイド ホーム目次前ページへ次ページへ索引


第 2 章

Fortran 入出力

この章では、Sun Fortran コンパイラが提供する入出力機能を説明します。

Fortran プログラムからファイルに探査する

プログラムとデバイスまたはファイルとの間でデータの転送は、Fortran 論理ユニットを通じて行います。論理ユニットは、入出力文において、論理ユニット番号で識別されます。論理ユニット番号は、0 から 4 バイト整数の最大値まで (2,147,483,647) です。

文字 * が論理ユニット識別子として現れることがあります。アスタリスクは、READ 文に現れたときは標準入力ファイル、WRITE 文または PRINT 文に現れたときは標準出力ファイルを表します。

Fortran 論理ユニットは、OPEN 文を通じて、特定の名前付きファイルに関連付けることができます。また、割り当て済みユニットは、プログラムの実行開始時に自動的に特定のファイルに関連付けられます。

名前付きファイルに探査する

OPEN 文の FILE= 指定子は、実行時に、名前付き物理ファイルへの論理ユニットの関連付けを行います。ファイルはあらかじめ存在しているものでもかまいません。また、プログラムの実行時に作成することもできます。OPEN 文に関する詳細は、『FORTRAN 77 言語リファレンス』を参照してください。

OPEN 文の FILE= 指定子は、簡単なファイル名 (FILE='myfile.out') を指定することも、絶対ディレクトリパスか相対ディレクトリパスを前に付けたファイル名
(FILE='../Amber/Qproj/myfile.out') を指定することもできます。また、指定子は、文字定数、変数、文字式のどれでもかまいません。

ライブラリルーチンを使用して、コマンド行引数と環境変数を文字変数としてプログラムに渡し、OPEN 文でファイル名として使用できます。詳細は、getarg(3F) と getenv(3F) のマニュアルページを参照してください。これらのライブラリルーチンとその他の有用なライブラリルーチンについては、『Fortran ライブラリ・リファレンス』でも解説しています。

次の例 (GetFilNam.f) は、入力された名前から絶対パスファイル名を作成する 1 つの方法を示しています。このプログラムは、ライブラリルーチンの GETENVLNBLNKGETCWD を使用して、$HOME 環境変数の値を取り出し、文字列中の最後の非空白を見つけ、現在の作業用ディレクトリを決定するものです。

      CHARACTER F*128, FN*128, FULLNAME*128
      PRINT*, 'ENTER FILE NAME:'
      READ *, F 
      FN = FULLNAME( F ) 
      PRINT *, 'PATH IS: ',FN
      END 

 
      CHARACTER*128 FUNCTION FULLNAME( NAME ) 
      CHARACTER NAME*(*), PREFIX*128
C       これは、C シェルを仮定しています。
C       絶対パス名は変更しません。
C       '~/' で名前を始めると、チルド(~)はホームディレクトリに
C       置換されます。
C       それ以外の場合、現在のディレクトリのパスを
C       相対パス名の前に置きます。
      IF ( NAME(1:1) .EQ. '/' ) THEN 
            FULLNAME = NAME 
      ELSE IF ( NAME(1:2) .EQ. '~/' ) THEN 
            CALL GETENV( 'HOME', PREFIX ) 
            FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 
&                         NAME(2:LNBLNK(NAME)) 
      ELSE 
            CALL GETCWD( PREFIX ) 
            FULLNAME = PREFIX(:LNBLNK(PREFIX)) // 
&                         '/' // NAME(:LNBLNK(NAME)) 
      ENDIF 
      RETURN 
      END

GetFilNam.f のコンパイルと実行の結果は、次のようになります。

demo% pwd
/home/users/auser/subdir
demo% f77 -silent -o getfil GetFilNam.f
demo% getfil
anyfile
/home/users/auser/subdir/anyfile
demo%

名前を指定しないでファイルを開く

OPEN 文には名前を指定する必要はありません。実行時システムがいくつかの規約に従い、ファイル名を補います。

一時ファイルとして開く場合

OPEN 文で STATUS='SCRATCH' を指定すると、システムは tmp.FAAAxnnnnn という形式の名前でファイルを開きます。nnnnn は現在のプロセス ID で置き換えられ、AAA は 3 文字の文字列、x は英字を示します。AAAx によってファイル名が一意になります。このファイルは、(f77 で) CLOSE 文に STATUS='KEEP' が指定されていない限り、プログラムの終了、または CLOSE 文の実行で削除されます。

すでに開いている場合

すでにプログラムによってファイルが開かれている場合、その後の OPEN 文にファイルの論理ユニット番号と変更するパラメータだけを指定して、ファイルの特性 (たとえば、BLANKFORM) を変更できます。

あらかじめ接続されたユニット

プログラムの実行開始時、3 つのユニット番号が自動的に特定の標準入出力ファイルに関連付けられます。あらかじめ接続されるユニットは、標準入力、標準出力、標準エラーです。

通常、標準入力は、ワークステーションのキーボードから入力を受け取ります。標準出力と標準エラーは、ワークステーションの画面に出力を表示します。

その他の場合、つまり、OPEN 文に論理ユニット番号を指定し、「FILE = 名前」を指定しない場合、ファイルは fort.n という形式の名前で開かれます。n は論理ユニット番号です。

OPEN 文を使用せずにファイルを開く

デフォルトの規約が想定できる場合、OPEN 文は使用しなくてもかまいません (任意です)。論理ユニットへの最初の操作が OPEN または INQUIRE 以外の入出力文である場合、ファイル fort.n が参照されます。n は論理ユニット番号です (特別な意味を持つ、0、5、6 を除きます) 。

これらのファイルは、プログラムの実行の前に存在する必要はありません。ファイルへの最初の操作が OPEN 文または INQUIRE 文でない場合、ファイルは作成されます。

例: 次のコード中の WRITE 文がユニット 25 に発行される最初の入出力文である場合、ファイル fort.25 が作成されます。

demo% cat TestUnit.f
    IU=25
    WRITE( IU, '(I4)' ) IU 
    END 
demo% 

このプログラムは、ファイル fort.25 を開いて、そのファイルに書式付き記録を 1 つ書き込みます。

demo% f77 -silent -o testunit TestUnit.f
demo% testunit
demo% cat fort.25
  25
demo%

ファイル名をプログラムに渡す

ファイルシステムは、Fortran プログラム中の論理ユニット番号を自動的に物理ファイルに関連付けるための機能をもっていません。

しかし、Fortran プログラムにファイル名を渡す方法はいくつかあります。

実行時引数と GETARG を経由する

ライブラリルーチン getarg(3F) を使用して、実行時にコマンド行引数を文字変数に読み込むことができます。引数はファイル名として解釈され、OPEN 文の FILE= 指定子で使用されます。

demo% cat testarg.f
        CHARACTER outfile*40
C  ユニット 51 の出力ファイル名として最初の引数を取得する。
        CALL getarg(1,outfile)
        OPEN(51,FILE=outfile)
        WRITE(51,*) 'Writing to file: ', outfile
        END
demo% f77 -silent -o tstarg testarg.f
demo% tstarg AnyFileName
demo% cat AnyFileName
 Writing to file: AnyFileName
demo%

環境変数と GETENV を経由する

同様に、ライブラリルーチン getenv(3F) を使用して、実行時に環境変数の値を文字変数に読み込むことができます。この値はファイル名として解釈されます。

demo% cat testenv.f
         CHARACTER outfile*40
C  ユニット 51 の出力ファイル名として $OUTFILE を取得する
         CALL getenv('OUTFILE',outfile)
         OPEN(51,FILE=outfile)
         WRITE(51,*) 'Writing to file: ', outfile
         END
demo% f77 -silent -o tstenv testenv.f
demo% setenv OUTFILE EnvFileName
demo% tstenv
demo% cat EnvFileName
 Writing to file: EnvFileName
demo%

getarg または getenv を使用するときには、前後の空白に気をつけなければなりません。(FORTRAN 77 プログラムはライブラリ関数 LNBLNK を、Fortran 95 プログラムは組み込み関数 TRIM を使用できます。) この章のはじめにある例の FULLNAME 関数行を用いれば、相対パス名を利用できるようにもプログラムできます。

f77: IOINIT を使用して論理ユニットをあらかじめ接続する

また、f77 においては、ライブラリルーチン IOINIT を使用して、実行時に論理ユニットを特定のファイルに接続することもできます。IOINIT は、ユーザーが指定した形式の名前を環境から検索し、対応する論理ユニットを、書式付き順番入出力用に開きます。名前は、一般形式の PREFIXnn でなければなりません。ここで、PREFIXIOINIT への呼び出しで指定するもので、nn は開く論理ユニットです。ユニット番号が 1 桁の場合は、先頭に「0」を付けなければなりません。詳細は IOINIT(3F) のマニュアルページを参照してください。IOINIT 機能は f95 には実装されていません。

例: 現在のディレクトリにある物理ファイル test.inptest.out に論理ユニット 1 と 2 を関連付けます。

まず、環境変数を設定します。

ksh または sh の場合:

demo$ TST01=ini1.inp
demo$ TST02=ini1.out
demo$ export TST01 TST02

csh の場合:

demo% setenv TST01 ini1.inp
demo% setenv TST02 ini1.out

ini1.f プログラムがユニット 1 を読み、ユニット 2 に書き込みます。

demo% cat ini1.f 
    CHARACTER PRFX*8 
    LOGICAL CCTL, BZRO, APND, VRBOSE 
    DATA CCTL, BZRO, APND, PRFX, VRBOSE 
&       /.TRUE.,.FALSE.,.FALSE., 'TST',.FALSE. / 
    CALL IOINIT( CCTL, BZRO, APND, PRFX, VRBOSE ) 
    READ(1, *) I, B, N 
    WRITE(2, *) I, B, N 
    END 
demo%

環境変数と ioinit を使用して、ini1.fini1.inp を読み取り、ini1.out に書き込みます。

demo% cat ini1.inp
 12 3.14159012 6
demo% f77 -silent -o tstinit ini1.f
demo% tstinit
demo% cat ini1.out
  12    3.14159  6
demo%

IOINIT は、このような形式でほとんどのプログラムで利用できます。ただし、このルーチンはユーザーが作成する同様のルーチンの例として利用できるよう、特に Fortran で書かれています。このプログラムのコピーは、FORTRAN 77 パッケージインストールの一部であるファイル/opt/SUNWspro/<release>/src/ioinit.f から入手できます。ただし <release> はソフトウェアのリリースごとに異なります (詳細についてはシステム管理者に問い合わせてください)。

コマンド行における入出力のリダイレクトとパイプ

物理ファイルをプログラムの論理ユニット番号と関連付けるもう 1 つの方法は、あらかじめ接続された標準入出力ファイルをリダイレクトまたはパイプする方法です。リダイレクトやパイプは、実行時の実行コマンド上で行われます。

この方法において、標準入力 (ユニット 5) を読み取り、標準出力 (ユニット 6) か標準エラー (ユニット 0) に書き込むプログラムは、リダイレクトによって (コマンド行上で <、>、>>、>&、|、|&、2>、2>&1 を使用することによって)、他の名前付きファイルを読み取ったり、書き込んだりできます。

これを次の表に示します。

表 2-1   csh/sh/ksh のコマンド行におけるリダイレクトとパイプ
動作 c シェルを使用する場合 Bourne または
Korn シェル を使用する場合
標準入力 - mydata
から読み取る
myprog < mydata myprog < mydata
標準出力 - myoutput
書き込む (上書き)
myprog > myoutput myprog > myoutput
標準出力 - myoutput
書き込む (追加)
myprog >> myoutput myprog >> myoutput
標準エラーをファイルに
リダイレクトする
myprog >& errorfile
myprog 2> errorfile
標準出力を他のプログラムの入力としてパイプする myprog1 | myprog2 myprog1 | myprog2
標準エラーと標準出力を他のプログラムにパイプする myprog1 |& myprog2 myprog1 2>&1 | myprog2


コマンド行におけるリダイレクトとパイプに関する詳細は、cshksh、 および sh のマニュアルページを参照してください。

f77: VAX/VMS 論理ファイル名

VMS FORTRAN から FORTRAN 77 に移植する場合は、INCLUDE 文の VMS 形式の論理ファイル名は UNIX のパス名にマップされます。環境変数の LOGICALNAMEMAPPING が、論理名と UNIX のパス名の間のマッピングを定義します。環境変数の LOGICALNAMEMAPPING が設定され -vax、 -xl、または -xld コンパイラオプションが使用されていると、コンパイラは INCLUDE 文にある VMS の論理ファイル名を解釈します。

コンパイラは、次の構文を使用して、環境変数に文字列を設定します。

    "lname1=path1; lname2=path2; ... " 

ここで、lname は論理名で、各 path はディレクトリの (末尾の「/」を除く) パス名です。この文字列を構文解析する場合は、空白文字はすべて無視されます。INCLUDE 文にあるファイル名から /list または /nolist は取り除かれます。ファイル名の論理名は、VMS ファイル名の中の最初のコロン (:) で区切られます。コンパイラは、次の形式のファイル名をその次にある書式に変換します。

    lname1:file

変換後:

    path1/file 

論理名では、大文字と小文字が区別されます。LOGICALNAMEMAPPING で指定されていない論理名が INCLUDE 文にあると、ファイル名は変更されずにそのまま使用されます。

直接探査入出力

直接探査入出力、つまりランダム入出力を使用すると、記録番号によってファイルに直接探査できます。記録番号は、記録が書き込まれたときに割り当てられます。順番入出力とは異なり、直接探査出力記録は、どのような順番でも読み取り、あるいは書き込みできます。しかし、直接探査ファイルでは、すべての記録が同じ固定長でなければなりません。直接探査ファイルは、そのファイルの OPEN 文の ACCESS='DIRECT' 指定子によって宣言されます。

直接探査ファイル中の論理記録は、OPEN 文の RECL= 指定子によって指定されたバイト長をもつ文字列です。READ 文と WRITE 文で、定義された記録サイズより大きな論理記録を指定してはなりません (記録サイズはバイト単位で指定されます)。論理記録のほうが短い場合は差し支えありません。書式なし直接探査書き込みでは、記録中の書き込まれていない部分は不定となります。書式付き直接探査書き込みでは、書き込まれていない記録は空白で埋められます。

直接探査の READ 文と WRITE 文には、REC=n 引数が追加されており、読み取りや書き込みを行う記録番号を指定するようになっています。

例 : 直接探査、書式なし

      OPEN( 2, FILE='data.db', ACCESS='DIRECT', RECL=200,
&             FORM='UNFORMATTED', ERR=90 ) 
      READ( 2, REC=13, ERR=30 ) X, Y 

このプログラムでは、ファイルを直接探査、書式なし入出力、200 バイトの固定記録長で開いた後で、13 番目の記録を XY に読み込みます。

例 : 直接探査、書式付き

      OPEN( 2, FILE='inven.db', ACCESS='DIRECT', RECL=200, 
&             FORM='FORMATTED', ERR=90 )
      READ( 2, FMT='(I10,F10.3)', REC=13, ERR=30 ) X, Y

このプログラムでは、ファイルを直接探査、書式付き入出力、200 バイトの固定記録長で開いた後で、13 番目の記録を読み取り、それを (I10,F10.3) の書式に従って変換します。

書式付きファイルの場合、書き込まれる記録のサイズは、FORMAT 文によって決定されます。上記の例では、FORMAT 文は記録を 20 文字 (またはバイト) に定義しています。並び上のデータの量が FORMAT 文で指定された記録長より大きい場合、1 つの書式付き書き込みで複数の記録を書き込むことができます。このような場合、各後続の記録には、連続する記録番号が割り当てられます。

例 : 直接探査、書式付き、複数記録書き込み:

    OPEN( 21, ACCESS='DIRECT', RECL=200, FORM='FORMATTED')
    WRITE(21,'(10F10.3)',REC=11) (X(J),J=1,100) 

直接探査装置 21 への書き込みによって、10 の要素からなる 10 の記録が作成されます。なぜなら、記録ごとに 10 要素であると書式で指定しているからです。これらの記録には、11 から 20 までの番号が割り当てられます。

バイナリ I/O

Sun Workshop Fortran 95 と Fortran 77 では OPEN 文の機能が拡張されて「バイナリ」の I/O ファイルを宣言できるようになりました。

ファイルを開くときに FORM'= BINARY' と指定すると、レコード長がファイルに組み込まれないことを除いて、FORM='UNFORMATTED' と大体同じ結果になります。このデータがなければ、1 レコードの開始点と終了点を知らせる方法がありません。そのため、後退する場所を知らせることができないので、FORM='BINARY' ファイルに対して BACKSPACE を実行できません。'BINARY' ファイルに対して READ を実行すると、入力リストの変数を設定するために必要な量のデータが読み込まれます。

内部ファイル

内部ファイルは、変数、部分列、配列、配列要素、構造化記録の欄のような、CHARACTER 型のオブジェクトです。内部ファイルからの READ の場合は、文字列の定数であってもかまいません。内部ファイルにおける入出力は、データをある文字実体から他のデータ実体に転送し、変換することによって、書式付き READWRITE 文をシミュレートします。ファイルの入出力は実行されません。

内部ファイルを使用するときには

例 : 内部ファイルから書式付きで順番に読み取ります (1 記録のみ)。

demo% cat intern1.f
    CHARACTER X*80 
    READ( *, '(A)' ) X 
    READ( X, '(I3,I4)' ) N1, N2 ! 内部ファイル X を読み取る
    WRITE( *, * )  N1, N2
    END
demo% f77 -silent -o tstintern intern1.f
demo% tstintern
12 99
  12  99
demo%

例 : 内部ファイルから書式付きで順番に読み取ります (3 記録)。

demo% cat intern2.f 
    CHARACTER  LINE(4)*16   ! これが「内部ファイル」
*                    12341234
    DATA  LINE(1) / ' 81  81 ' /
    DATA  LINE(2) / ' 82  82 ' /
    DATA  LINE(3) / ' 83  83 ' /
    DATA  LINE(4) / ' 84  84 ' /
    READ( LINE,'(2I4)') I,J,K,L,M,N  .
    PRINT *, I, J, K, L, M, N
    END
demo% f77 -silent intern2.f 
demo% a.out 
   81  81  82  82  83  83 
demo%

例 : 内部ファイルから直接探査で読み取ります (1 記録) (f77 のみ)。

demo% cat intern3.f 
    CHARACTER LINE(4)*16   ! これが「内部ファイル」
*                    12341234
    DATA  LINE(1) / ' 81  81 ' /
    DATA  LINE(2) / ' 82  82 ' /
    DATA  LINE(3) / ' 83  83 ' /
    DATA  LINE(4) / ' 84  84 ' /
    READ ( LINE, FMT=20, REC=3 ) M, N   
20  FORMAT( I4, I4 ) 
    PRINT *, M, N 
    END 
demo% f77 -silent intern3.f 
demo% a.out 
   83  83 
demo%

f77: テープ入出力のみ

通常、ほとんどの Fortran の入出力はディスクファイルに対して行われます。しかし、OPEN 文を経由して論理ユニット番号を物理的にマウントされたテープドライブに関連付けることによって、テープに直接入出力できます。

磁気テープに入出力する場合、Fortran の入出力文よりも、TOPEN() ルーチンを使用するほうが効果的です。

TOPEN ルーチンを使用する

非標準のテープ入出力パッケージ (topen(3F) のマニュアルページを参照) を使用して、テープドライブと、Fortran の文字変数として宣言されたバッファの間でブロックを転送できます。その次に、内部入出力を使用して、このバッファを満たしたり空にしたりすることができます。ただし、この機能は他の Fortran 入出力との統合性はなく、テープの論理ユニットの独自のセットを持っています。詳細は、マニュアルページを参照してください。

テープに対する Fortran の書式付き入出力

Fortran の入出力文では、磁気テープ上にある書式付きの順番ファイルに対して透過な探査ができるようになっています。書式付きの記録長には制限がなく、また、記録が複数のテープブロックにわたってもかまいません。

テープに対する Fortran の書式なし入出力

Fortran の入出力文は、磁気テープと接続して書式なし探査を行うにはあまり適していません。書式なし記録では、記録長 (オーバーヘッドとして 8 文字を加算) はバッファサイズを超えることはできません。

この制限のため、入出力システムは複数の物理テープブロックにわたる記録の書き込みを行いませんが、必要に応じて短いブロックの書き込みは行います。書式なし記録のこの形式は、テープに対しては不適切でも保持されるので、ファイルをディスクとテープ間で自由にコピーできます。

記録が複数のブロックに渡れないという制限はテープの読み取りには適用されないため、特別な配慮をせずにファイルをテープからディスクにコピーできます。

テープファイルの形式

Fortran のデータファイルはテープ上では、最後にファイル終了記録がある、連続するデータ記録という形式で書き込まれます。データはブロックにグループ化されており、最大長はファイルを開くときに決定されます。記録は、ディスクファイルの記録と同じ形式になります。書式付き記録の最後には改行文字があり、また書式なし記録の前後には文字カウントがあります。一般的には、Fortran の記録とテープブロックの間には何も関係がありません。つまり、記録は複数のブロックにわたることができ、ブロックは複数の記録の一部を含むことができます。

唯一の例外は、Fortran は複数のブロックにわたる書式なし記録を書き込まないことです。このため、書式なし記録の最大長は、ブロック長より 8 文字小さくなります。

dd 変換ユーティリティ

Fortran のファイル終了記録は、テープマークに直接マップされます。したがって、Fortran ファイルは、テープシステムファイルと同じ形式になります。しかし、テープ上の Fortran ファイルの形式は、UNIX の他の部分で使用されている形式と同じであるため、Fortran プログラムは、テープから 80 カラムのカードイメージを読み取ることができません。既存の Fortran プログラムと、それを使用して読もうとする既存のデータテープがある場合には、dd(1) ユーティリティを使用してテープを変換し、改行文字の追加と終端の空白文字の消去を行う必要があります。

例 : mt0 上のテープを変換し、それを実行可能ファイルの ftnprg にパイプします。

demo% dd if=/dev/rmt0 ibs=20b cbs=80 conv=unblock | ftnprg 

getc ライブラリルーチン

dd を使用せずに、getc(3F) ライブラリルーチンを呼び出して、テープから文字を読み取ることができます。読み取った文字を文字変数に格納し、内部入出力を使用して書式付きデータを転送します。TOPEN(3F) のマニュアルページも参照してください。

ファイルの終了

READ 文の実行中にファイル終了記録に行き当たると、ファイル終了条件に到達したことになります。標準規格では、ファイルはファイル終了記録の後に位置付けられることになっています。これは、実際にはテープの読み取りヘッドが、テープ上の次のファイルの開始位置に留まることを意味しています。したがって、テープ上の次のファイルの読み取りを続けることができるように思えますが、これは厳密には正しくありません。『ANSI FORTRAN 77 Language Standard』にはカバーされていません。

また規格では、BACKSPACE 文か REWIND 文を使用してファイルの位置付けのやり直しを行うことができると規定しています。これは、ファイルの終端に到達した後、ファイル終了記録を超えて巻き戻しを行い、さらにファイルを操作できるということです。たとえば、 終わりに記録を書き足す、ファイルを巻き戻す、ファイルを再度読み取る、または書き込むなどのファイル操作が可能です。

マルチファイルテープ

テープファイルを開くときに使用する名前によって、記録密度や、テープを開いたり閉じたりするときに自動的にテープの巻き戻しを行うかなど、接続に関するいくつかの性質が決まります。

マルチファイルテープ上のファイルに探査する場合には、mt(1) ユーティリティを使用して適切なファイルにテープを位置付け、それからそのファイルを /dev/nrmt0 のような自動巻き戻しをしない磁気テープとして開きます。この名前でテープを使用すると、閉じるときの位置付けのやり直しも行われません。プログラムがファイルの終わりまで読み取りを行うと、次に開いたときに、テープ上の次のファイルに探査できるようになります。以後のプログラムはすべて、最後の探査位置 (なるべくファイルの先頭かファイル終了記録を通り過ぎた位置) からテープを探査できます。

プログラムが何らかの異常で途中終了した場合、テープは予測できない場所に位置付けられている可能性があります。SunOS mt(1) コマンドを使用して、テープを適切な場所に位置付けし直します。

Fortran 95 の入出力について

Sun WorkShop 6 FORTRAN 77 と Fortran 95 の入出力には互換性があります。f77f95 のコンパイルが混在する実行ファイルは、プログラムの f77 および f95 部分のどちらからも同じ装置に対して入出力を行えます。

ただし、Fortran 95 には次のような新しい機能が追加されています。


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引