導入: なぜRECLの単位を気にする必要があるのか
Fortranでバイナリファイルを扱う際、直接アクセス(Direct Access)は特定のレコードへ高速にジャンプできるため非常に強力です。しかし、この際に避けて通れないのが「RECL(レコード長)の単位」問題です。多くのエンジニアが「RECLはバイト単位だ」と信じて実装し、別のコンパイラや環境に移行した途端にI/Oエラーに悩まされます。実は、RECLの単位はコンパイラ依存であり、ある環境では「1バイト」、別の環境では「4バイト単位(ワード)」と解釈されることがあるからです。この不確実性を排除し、環境に依存しない堅牢なコードを書くことが、プロの数値計算エンジニアへの第一歩です。
基礎知識: RECLとIOLENGTHの仕組み
直接アクセスファイルをオープンする際、`OPEN`文の`RECL`指定子で各レコードの長さを指定します。問題なのは、この値が「ファイル上で何バイトを占めるか」を指すのか、「何ワード(4バイトずつ)を占めるか」を指すのかが、規格で厳密に定められていない点です。
これを解決するために用意されているのが、`INQUIRE`文の`IOLENGTH`指定子です。これは「特定の変数を書き出すために必要なレコード長を、そのコンパイラが期待する単位で返す」という非常に便利な機能です。これを使えば、ハードウェアやコンパイラの差異を意識せずに済みます。
実装/解決策: INQUIRE文による動的な長さ取得
解決策はシンプルです。固定値(例えば`RECL=100`など)をマジックナンバーとして記述するのではなく、書き込みたいデータ構造を用いて事前に`INQUIRE`文を実行し、その結果を変数に格納して`OPEN`文に渡すだけです。
サンプルプログラム: ポータブルな直接アクセスI/O
以下は、倍精度実数配列を安全に直接アクセスファイルへ書き込むためのサンプルコードです。
program secure_io
implicit none
integer :: i, recl_val, iostat
double precision, dimension(10) :: data_array
! 書き込みたいデータでIOLENGTHを調査する
! この一文により、コンパイラがRECLとして期待する単位を自動計算する
inquire(iolength=recl_val) data_array
! 調査した長さをRECLに渡すことでポータビリティを確保
open(unit=10, file='data.bin', access='direct', &
status='replace', recl=recl_val, iostat=iostat)
if (iostat /= 0) then
print , "ファイルオープン失敗"
stop
end if
! データの書き込み(第1レコード目)
write(10, rec=1) data_array
close(10)
print , "書き込み完了。RECL単位値:", recl_val
end program secure_io
応用・注意点: 現場での運用と注意点
この手法を用いる上で注意すべき点がいくつかあります。
1. 構造体の扱いに注意
派生型(Derived Type)を書き込む場合、コンパイラによってパディング(データ間の隙間)の入り方が異なることがあります。`INQUIRE`は現在のコンパイラのメモリレイアウトに基づいた長さを返しますが、書き込み側と読み込み側でコンパイラの設定が異なると、バイナリ互換性が崩れます。クロス環境でデータをやり取りする場合は、バイナリ形式ではなく、NetCDFやHDF5などの標準フォーマットを検討してください。
2. 配列サイズとRECL
`INQUIRE`はあくまで「その変数を書き込むのに必要な長さ」を返します。もしレコード単位を「変数の個数」ではなく「特定の固定サイズ」にしたい場合は、ダミー変数を用意して`INQUIRE`をかけるなどの工夫が必要です。
3. 読み書きの整合性
書き込み時に`INQUIRE`で取得した長さと、読み込み時に指定する長さが一致していることが大前提です。プログラムを分ける場合は、RECLの値をファイルヘッダーに記録しておくか、同一の設定ファイルを読み込む設計にしましょう。

コメント