Fortran/入出力文

Fortranや他の言語では、どこにどのように印刷したり読んだりしてほしいかを指定することは、しばしば有用です。Fortranには、このような目的のために、多くのコマンドや書式指定が用意されています。以下のセクションでは、I/O操作 (open, close, inquire, rewind, backspace, endfile、flush、print、read、write、namelist)とI/Oフォーマット(format)があります。Fortran 2008では、基本的な機能をユーザー定義のルーチンで拡張し、他の派生型で構成されたものも含めて、派生型を出力できるようになったことが大きな特徴です。
これらのコマンドを組み合わせることで、フォーマットされたファイルやフォーマットされていないファイルをシーケンシャル、ダイレクト、非同期アクセスで読み書きするための、非常に強力な機能群が形成されます。確かに、最初はオプションが多すぎて戸惑うかもしれません。しかし、基本的な操作は簡単ですが、ほとんどのファイルを読み書きできるパワーと柔軟性に支えられています。
しかし、現段階では、言語定義の観点から、Fortranが単純かつ直接的にできないことについて言及しておく必要があります。FortranはURLで定義されたファイルを扱うことはできません。ファイルはローカルにあるか、マップされたネットワークドライブかそれに相当するものでなければなりません。同様に、FortranはXMLをネイティブにサポートしていません。ただし、XMLはシンプルなASCIIテキストなので簡単に読むことができますが、それを解析するのはプログラマーの仕事です。Fortran言語はコンピュータグラフィックスについて何も知らないので、言語で定義された描画コマンドを見つけることはできません。Fortranはjpgファイルを喜んで開いて読みますが、そのファイルを画像として表示する言語定義の方法はありませんので、適切な外部ライブラリを使用する必要があります。最後に、Fortranには言語的に定義されたマウス操作やタッチスクリーンのジェスチャーがありません。
現代のFortranは、I/O操作のための豊富な語彙を持っています。これらの操作は一般的に、画面やキーボード、外部ファイルや内部ファイルに対して使用できます。最近のバージョンのFortranでは、これらのコマンドの構文は合理化されていますが、後方互換性のために元の構文のほとんどは残されています。I/O操作はエラーが発生しやすいことで知られていますが、Fortranではエラーを特定して処理するための統一されたメカニズムをサポートしています。
これは古典的な「Hello World」操作ですが、プロダクション・コードではほとんど使われません。printは、2つのフォーマットされた出力操作のうちの1つで、write文よりもはるかに単純です。print文の主な目的は、スクリーン(標準出力単位)に印刷することであり、ファイル出力のオプションはありません。一般的な形式は
fmtとlistは共にオプションであり、 fmtは明示的なものとリスト指向のもの(*で示される)があり、 オプションの場合はname=valueの形式をとることができます。リストは、リテラルまたは固有の型変数のコンマ区切りのリストです。では、いくつか例を挙げてみましょう。
printは、iostatやiomsg句をサポートしていない唯一のI/O操作であり、この理由だけでも、一時的な出力やデバッグを除いて、新しいコードで使用すべきではないことに注意してください。printは、ユーザ定義の型を印刷するための明示的なメカニズムを持っておらず、これもプロダクション・コードで使用しない理由のひとつです。
上記のprintの例では、print文は、コンピュータの画面として知られている標準出力装置に自動的に接続されています。しかし、一般的にFortranでは、コードを外部ファイルに接続するために2段階のプロセスが必要です。まず、openコマンドにより、ファイルをFortranのチャンネル(正の整数で手動で識別するか、負の値を自動的に割り当てる)に接続しなければなりません。開かれていないチャンネルへのreadおよびwrite操作はエラーとなる。該当するチャンネルが開かれるまで、言語で指定されたバッファリングは行われない。I/O操作が完了すると、ファイルとFortranチャンネルの間の接続をcloseすることができます。ファイルへのチャネルが閉じられる前に Fortran プログラムが終了した場合、 Fortran は通常、データの大きな損失なしにチャネルを閉じます。
Fortranチャンネルの利用可能な状態は、inquireコマンドの一つの形式を通して確認することができます。inquireコマンドは、Fortranチャンネルに接続される前に、 ファイルの存在やその他のプロパティを決定するためにも使用できます。
内部ファイルへのFortran I/Oは、接続前の処理を必要としません。キーボードからのFortran入力と画面への出力は、自動的に特別なチャンネル(*)に事前接続されます。コンパイラベンダはこれらの標準I/Oデバイスに自由にチャネル番号を割り当てることができ、ユーザは組込みモジュールiso_fortran_envを介してどのチャネル番号が使用されているかを知ることができます。
これは、外部ファイルとFortranチャンネルの間の接続を確立するために必要なコマンドです。openコマンドは、新規ファイルの作成や既存のファイルへの接続に使用できます。一度オープンしたファイルへの後続のI/Oは、このチャンネル番号を介して行われます。openコマンドには、ファイルが既に存在しているか、既に存在していないかを確認したり、入力のみ、出力のみ、または両方に使用されることを確認するオプションがあります。ファイルの期待されるフォーマットをopenコマンドで指定し、エラーをトラップすることができます。コマンドの完全な構文はかなり複雑に見えるかもしれませんが、一般的には、openの1回の呼び出しは、利用可能なすべてのオプションの小さなサブセットのみを使用します。
openコマンドは、外部ファイルが通常カード・イメージであったときに生まれました。openは現在、ファイルへの接続が固定フォーマット、非同期、バイナリ・ストリーム、およびこれらの多くの組み合わせであることを指定できます。I/Oは潜在的なコーディング・エラーの主な原因であり、重要なデータを読み込んだ場合は、正しい処理を確認するために再度書き込む必要があることを覚えておくとよいでしょう。
Fortranのチャンネル番号の値は、Fortranプログラムの1つのイメージの中でグローバルなスコープを持ちます。チャンネルを開くために整数変数を使用し、その変数のスコープが非常に限られていたとしても、実際のチャンネル番号は事実上どこにでも存在します。あるモジュールがチャンネル10をオープンし、別のモジュールがチャンネル10をクローズしても、それらの間には何の使用関連性もないため、設計時にこの点を考慮する必要があります。このため、大規模なプログラムでは、1つのモジュールですべてのファイルI/O操作を制御し、"open - read/write - close" という明確な連鎖を維持できるようにすることがよくあります。
最後に、通常の Fortran と同様に、新しいコードに使用してはいけないレガシー目的のために保持されているオプションや構文があります。
ここで、[]はオプションのセクションを示し、olistはオプションのコンマ区切りのリストです。上の例では、uはスカラーの整数式またはそれに相当するもので、newunitオプションが指定されていない限り必須です。(不運なことに、1つのopen文で複数のファイルを開くことはできません)。技術的には、uは外部ファイルユニット番号、略してチャネル番号と呼ばれます。
newunit=nu ここで nu はデフォルトの整数変数です。これにより、プロセッサはチャネル番号を選択することができ、レガシーコードとの衝突を避けるために、現在使用されているユニット番号と衝突しない負の値(-1ではない)が選択されます。これは、すべての新しいコードで使用されるべき形式です。
iostat=ios iosはデフォルトの整数変数で、open文がエラーを検出しない場合は0に設定されますが、エラーが発生した場合は正の値に設定されます。技術的にはオプションですが、これはすべてのopenコマンドで強く推奨されるオプションです。このオプションが存在しない場合 (および err= オプションが存在しない場合、以下を参照) は、エラーが発生した場合にプログラムが停止します。このオプションが存在すると、プログラマは返された値をチェックし、それに応じてプログラムを動作させる責任を負うことになる。
iomsg=iom ここで、iomはデフォルトの種類のスカラ文字変数である。繰り返しになりますが、技術的にはオプションですが、新しいコードのすべてのopenコマンドには、このオプションを強く推奨します。メッセージの長さは、エラーやベンダーに依存するので、試行錯誤が必要かもしれません。
file=fln flnは、外部ファイルの名前を指定するデフォルトの文字変数、リテラル、または式です。ファイル名は、完全修飾パスまたはローカルファイル名です。パスがネットワークドライブ上のファイルを指している場合、そのドライブは事前に接続されている必要があり、この接続を行うための言語定義された方法はありません。(ただし、execute_command_lineに頼ることはできます)
status=stn ここで stn は、デフォルトの文字変数、リテラル、または式で、(大文字小文字に関係なく) 'old'、'new'、'replace'、'scratch'、'unknown' のいずれかに評価されなければなりません。old」は、ファイルが存在していることが必要で、通常、open文の目的がファイルの読み取りである場合に使用されます。'new' と 'replace' は、上述のfile=オプションの存在を必要とし、'new' はファイルが存在しないことを必要とし、'replace' はファイルがすでに存在していてもよいが、存在している場合は上書きされる。'scratch' は特殊で、file=オプションを使用してはならず、作成されたファイルは後にcloseコマンドを実行しても保持されない。'scratch' は通常、大きなデータ構造をハードディスクや同様の大容量記憶装置に一時的に保存するために使用されます。'unknown' が指定された場合、これは status= オプションが与えられていない場合のデフォルトでもあり、ファイルの状態はベンダーやシステムに依存するようになり、マニュアルを参照しなければなりません。
action=act ここで act は、'read'、'write'、'readwrite' と評価されるデフォルトの種類の文字式、変数、または値です。驚くべきことに、デフォルトはプロセッサに依存するため、マニュアルを参照する必要があります。'read' が指定された場合、ファイルは読み取り専用とみなされ、このチャンネルで write, print, end file ステートメントを実行しようとするとエラーになります。同様に、'write' が指定された場合、ファイルは書き込み専用とみなされ、readステートメントを実行しようとするとエラーになる。'write' が指定された場合、他のいくつかのステートメントは、プロセッサに依存した方法でエラーになることがあります (例: backspace)。
access=acl ここで acl は、'sequential'、'direct'、'stream' のいずれかで評価される文字式、変数、またはリテラルです。既に存在しているファイルを開く場合、この値は許可された値に対応していなければなりません。この値は通常、ファイルが作成されたときに与えられた値です。新しいファイルを開くときのデフォルトは 'sequential' です。'stream' アクセスは Fortran 2008 の新機能で、C のバイナリストリームファイルとの互換性があります。ストリーム」アクセスのもう一つの重要な機能は、ファイルを書き込み用に配置し、ファイルの残りの部分を変更することなくファイルの一部を上書きできることです。フォーマットされたストリームファイルの場合、 new_line(nl)関数は、関連する改行文字を文字変数 nl に返します。
recl=rcl ここで rcl は正の値に評価されなければならない整数式、変数またはリテラルである。ファイルが直接アクセスのために開かれる場合、この「オプション」は必須であり、 各レコードの長さを指定しなければならない。シーケンシャルファイルの場合はオプションで、レコードの最大長を指定するために使用できます。すでに存在するファイルの場合、rclの値はファイルの作成に使用された値と一致しなければならない。どのような場合でも、rclの値は、基礎となるオペレーティングシステムで許可されていなければならない。
form=frm frmは、'formatted' または 'unformatted' と評価される文字式、変数またはリテラルである。デフォルトでは、'sequential' アクセスの場合は 'formatted' 、'direct' アクセスの場合は 'unformatted' となるため、このオプションは省略できることが多い。
blank=blk ここで、blkは文字式、変数、またはリテラルであり、フォーマットされたi/oのみで 'null' または 'zero' の値を提供する。以下のbnおよびbzフォーマットを参照。
position=psn ここでpsnは、 'asis'、 'rewind' または 'append' として評価される文字式、変数またはリテラルであり、アクセス方法がシーケンシャルの場合にのみ適用される。初期値は 'asis' です。開くとき、新しいファイルは常に初期位置に配置されますが、既存のファイルの場合、ユーザーは現在の位置をどこに配置するかを選択することができます。
delim=
pad=
世の中には多くのレガシーコードがありますが、このセクションでは、まだ有効ではあるものの置き換えを検討すべきであり新しいコードでは絶対に使用してはならない機能について説明します。
err=eno enoはリテラルの整数のラベル番号です。open文の処理でエラーが発生した場合、プログラムはラベル番号 eno の文に制御を移します。err=オプションがあると、エラーが発生した場合にプログラムが続行されました。このオプションは、現在では iostat= と iomsg= で置き換えるべきです。(err=とiostat=の両方を指定することは有効ですが、どちらもないとopen文の処理でエラーが発生した場合にプログラムが停止してしまいます)。
unit=nu ここで、nuはデフォルトの整数式、変数、リテラル値で、正の値でなければならず、既に使用されているどの単位とも一致してはならない。このオプションがオプションのリストの最初に置かれている場合、unit= は省略できます。これは非常に広く使われていましたが、現在ではnewunit=に置き換えられるべきです。非常に古いコードでは、nuは固定値であり、プログラマは同時に使用されている他のチャンネルと衝突しないようにしなければなりませんでした。最近では、inquireステートメントは、まだ使用されていないユニット番号を選択するために使用することができますが、これは後続のopenステートメントが既に使用されている固定値を使用しようとすることを防ぐことができませんでした。これが、newunitオプションだけが、チャンネル番号に負の値を指定することができる理由です。
read文は、指定された形式の入力から、変数を読み出す文である。たとえば、以下のようになります。
このコードは、a用の整数メモリ領域を確保し、デフォルトの入力からデフォルトのフォーマットで値を読み込み、それをaに格納します。(*,*)の最初の*は、値がどこから読み込まれるかを意味する。2番目の*は、ユーザーが数値を読み取る際に必要なフォーマットを指定します。まず、利用可能なフォーマット文字列について説明します。Fortranでは多くのフォーマット文字列が用意されており、画面上での数値や文字列の表示方法を指定することができます。固定小数点のリアルの場合 Fw.d; wは数値に割り当てられたスペースの総数、dは小数点以下の桁数です。小数点以下の位置は常に1つの位置を占めます。たとえば、以下のようになります。
I/Oフォーマット(例:'(F5.2)')の詳細は以下の通りです。
inquire文には2つの基本的な形があります。「inquire by unit」と「inquire by file」で、どちらも非常に便利で、知っておく価値があります。inquire by length "と呼ばれるより曖昧な形式もありますが、 これは、必要なレコード長を決定するために、潜在的な出力のフォーマットされていない レコード長をチェックしたり、すでに定義されたレコード長を持つファイルが 与えられた出力に対応できるかどうかをチェックするのに便利です。
inquireコマンドのやや曖昧なバージョンは、 与えられた形式の出力を含むために必要な、フォーマットされていない レコードの長さを取得するために使用され、ユーザは必要なレコードの 長さを確認したり指定したりすることができます。
closeコマンドは、ファイルとFortranチャンネルの間の接続を解除します。その過程で、ファイルがどのように開かれたかに応じて、ファイルは保存されたり、破棄されたりします。closeコマンドの一般的な形式は以下の通りです。
ここで、uはクローズするチャンネルの番号として評価されるデフォルトの整数式、変数、リテラル値で、unit=はオプションです。オプション・リストで使用できるオプションは以下のとおりです。
iostat=ios iosはデフォルトの整数変数で、closeコマンドが正しく実行された場合には値0を返します。エラーが発生した場合には、戻り値は正の値となり、後述のiomsgオプションによってエラーを説明するメッセージが提供される。
err=eno ここでenoはリテラルの整数のラベル番号です。close文の処理でエラーが発生した場合、プログラムはラベル番号enoの文に制御を移します。err=オプションがあると、エラーが発生した場合にプログラムが続行されていました。このオプションは、現在では iostat= と iomsg= で置き換えるべきである。(err=とiostat=の両方を指定することは合法ですが、どちらも指定しないとopen文の処理でエラーが発生した場合にプログラムが停止してしまいます)。
iomsg=iom ここで、iomは、デフォルトの種類のスカラ文字変数です。繰り返しになりますが、技術的にはオプションですが、新しいコードのすべてのcloseコマンドには、このオプションを強く推奨します。メッセージの長さはエラーやベンダーに依存するので、試行錯誤が必要かもしれません。
status=st
直感的ではないかもしれませんが、Fortranはすでに閉じられているチャネルをCLOSEしようとすることをエラーとはみなしません。inquireやopenのように、 closeが報告するエラーは、事実上のオペレーティングシステム・エラーです。例えば、既に閉じられているチャネル上で status="delete" を持つ close は、特にファイルがもはや存在しない場合にはエラーとなります。同様に、Fortranでは、'scratch' として作成されたファイルをstatus="keep"でクローズするとエラーになります。これらの制限は、iostat(およびiomsg)句が、ユーザが必要に応じて緩やかな終了をプログラムするために使用されることを前提としており、closeコマンドのパフォーマンスに関する完全なレポートを得るためではありません。
明示的なフォーマットについては後述しますが、「言語の中の言語」というものが存在することはすぐにわかりますので、Fortranではショートカット、つまり言語で定義されたフォーマットの推測を行います。このデフォルトフォーマットは、入力用のカンマ区切り変数(CSV)プロセッサに非常に近いことがわかります。リスト指向のI/Oはfmt=*節で指定しますが、fmt節はオプションで、単に*で置き換えることができます。
Fortranには、I/O操作のフォーマットを制御するための、豊富だが非常に簡潔な言語があります。フォーマット・コマンドは明示的なfortmat文の中に置くことができ、また、関連するREADまたはWRITE文の節の中に文字通り置くことも、character変数に格納することもできます。