「入出力のすべて」
能書き
Fortranで柔軟な入出力を行うのは困難です。が、使いこなせばそれなりのことは出来るようになります。ここで紹介する知識はFortran限定でしか使えません、4年生の皆さんはあまりこだわらないこと。
入出力オプション
openのオプション
open文には色々とオプションをつけることができます。open(UNIT,FILE[,STATUS][,ACTION][,POSITION][,IOSTAT]) ・UNIT=装置番号 非負整数:別解説参照 ・FILE=ファイル名 文字列:相対パス・絶対パスどちらでも可 ・STATUS 'NEW':ファイルが既に存在するとエラー 'OLD':ファイルが存在しないとエラー 'REPLACE':ファイルが無ければ作成、あれば削除してから作成 'UNKNOWN':(デフォルト) ・ACTION 'READ':読み込み専用 'WRITE':書き込み専用 'READWRITE':(デフォルト) ・POSITION 'APPEND': write:消去せず最後尾に追記 'REWIND':(デフォルト)read:1行目から読む write:消去して新しく ・IOSTAT 整数型変数:入出力エラーコードを返す(正常なら『0』を返す) 指定すると、エラーが起きても続行。指定しない場合エラーで即座に停止付ける際は、
引数名=値(もしくは変数)の形。
・装置番号
ファイル入出力は、open文でファイルのID(装置番号)を設定した後、 そのIDを通して行われる。
ただし以下の番号には最初から装置が割り当てられている。
UNIT=5:コンソール(キーボード・標準)入力 UNIT=6:コンソール(画面・標準)出力 UNIT=0:エラー出力装置(画面)これらの番号を上書きしても特に問題はないが、2桁の数字(10-)を使うのが慣例。
openいろいろ
・入力ファイルの丁寧なopeninteger :: errorCode open(10,file="parameter.txt",status='OLD',action='READ',position='REWIND',iostat=errorCode) if(errorCode/=0) then print *, "IOERROR >> there is no 'parameter.txt'" stop end if『iostat』とエラー処理は省いても良い。
・出力ファイルのopen:一般
integer :: errorCode open(11,file="result.txt",status='REPLACE',action='WRITE')
・出力ファイルのopen:上書き禁止
integer :: errorCode character(LEN=128) :: resultFile read *, resultFile open(11,file=resultFile,status='NEW',action='WRITE',iostat=errorCode) if(errorCode/=0) then print *, "IOERROR >> '"//trim(resultFile)//"' already exists." stop end if『iostat』とエラー処理は省いても良い。
・出力ファイルのopen:既存のファイルを残し、そこにデータを書き足す
open(11,file="result.txt",action='WRITE',position='APPEND')
read, writeのオプション
read, write文にも色々とオプションをつけることができます。read(UNIT,FMT[,IOSTAT]) ・UNIT=装置番号 非負整数:上記参照 ・FMT=フォーマット 文字列:上記参照 ・IOSTAT 整数型変数: 指定すると、エラーが起きても続行。指定しない場合エラーで即座に停止 0 : 正常 -1 : EOF(ファイルの終わりに到達) 正数 : エラー(エラーコードを返す)
write(UNIT,FMT[,ADVANCE]) ・UNIT=装置番号 非負整数:上記参照 ・FMT=フォーマット 文字列:上記参照
・ADVANCE=改行有無 'yes'/'no': defaultは'yes' ADVANCE='no'を指定すると、出力後に改行されない。 FMTを具体的に指定しないと(*にすると)エラーとなる。
出力のフォーマット
定義:フォーマット
print '(フォーマット)', {値} write(ファイルID,'(フォーマット)') {値}『フォーマット』のところに「編集記述子」のリストをカンマ区切りで並べることで、出力形式を指定する。
『'(フォーマット)'』の代わりに『*』とすると、自動で設定される。
read文も指定は出来るが、普通は『*』(自動)で良い。
編集記述子一覧
・整数
Iw[.m] : 整数 [m桁に満たない場合は0で埋める。例: 001] *(拡張機能?) w=0とすると、最低幅で左寄せ
w7 '(I7)' : 1234 '(I7.6)': 001234 m6 w0 '(I0)' :1234・実数
Fw.d : 小数点 (w >= d+3) *(拡張機能?) w=0とすると、最低幅で左寄せ Ew.d[ex] : 指数表示(例:-0.##E+10) (w >= d+7) 仮数部の絶対値が0.1から1.0の間(0.100...〜0.99...)になる。 指数部はx桁(デフォルトは環境依存) ESw.d[ex] : 理学表記指数(w >= d+7) 仮数部の絶対値が1から10の間(1.00...〜9.99...)になる。 ENw.d[ex] : 工学表記指数 指数が3の倍数,仮数部の絶対値が1から1000の間(1.00...〜999.99...)になる。 Dw.d :(倍精度実数。指数記号EがDになるだけ。) Gw.d : 絶対値の大きさによって,F型とE型を使い分ける(Fortran2008以降だと、整数や文字列型にも使える)
w13 '(F13.4)' : -123456.7890 d4 w13 '(E13.4)' : -0.1234E+06 d4 w13 '(E13.4e4)':-0.1234E+0006 d4 x4 w13 '(ES13.4)' : -1.2345E+05 d4 w13 '(EN13.4)' :-123.4567E+03 d4 w13 '(G13.4)' : 0.6022E+24 '(G13.4)' : 2.7182
注:環境によって指数部の表示桁数が違うかもしれない。
・その他
nX : 空白n個 (n省略不可) Aw : 文字列 (w省略可能) 左寄せ Tn : タブ揃え 次の印字をn文字目から開始 / : 改行 カンマはいらない $ : 改行しない(停留入出力) "文字":そのまま出力される
私自身、全て使っているわけではないので少々あいまい。
フォーマットに変数を使う(拡張機能)
フォーマットの中で使いたい変数を< >で囲む。<nx>ES<digit+7>.<digit>拡張機能なので、ifort以外の環境では使えないかも。
文字列の操作
定義:文字列型変数の操作
文字列の結合 文字列//文字列
文字列の右側の余白をトリミングする関数 trim(文字列)
文字列を左詰にする関数 adjustL(文字列)
trim関数は右側の余白しか削ってくれないので、左の余白も削除したい場合は『trim(adjustL(文字列))』とする。
学習:文字列型
文字列の代入:文字列を代入する際は、左詰で代入される。よって、短い文字列を代入すると右側に余白ができ、長い文字列を代入すると右側が切り捨てられる。
文字列型変数は、1次元部分配列のように要素指定が出来る。
str = "1234567890" print *, str(1:5) str(6:8) = "abc" print *, str(2:)
12345 2345abc90
1文字だけ指定したい場合でも、上限と下限を指定しなければならない。例えば『str(2:2)』とする。『str(2)』は不可。
次の関数を利用すると、多少高度な処理が可能になる。
検索文字列が最初[最後]に出てくる開始位置を返す関数 index(文字列変数,検索文字列[,back])例)ファイル名(拡張子の前)に文字列を追加する
fileName = "test.txt" print *, "input file : ", trim(fileName) mainPart = fileName(1:index(fileName,".",back=.true.)-1) extension = fileName(index(fileName,".",back=.true.):) fileName = trim(mainPart) // "_new" // trim(extension) print *, "file type : ", trim(extension(2:)) print *, "new file name : ", trim(fileName)
input file : test.txt file type : txt new file name : test_new.txt
Tips (裏技?):変数を文字列にする
定義:文字列型変数への数値の代入
『変数』の値を『文字列変数』に格納 write(文字列変数,'(フォーマット)') (数値型)変数
テキストファイルに書き込むのと同じ要領である。
ファイル名の自動生成
write文の装置番号の代わりに変数を入れると、その変数に書き込むことができます。具体例:
整数型変数『n』の値を文字列型変数『chn』に格納(左詰) write(chn,'(i0)') nこれにより、実行時パラメータをファイル名にすることが可能になります。 すなわち、
write(chp,'(i3.3)') int(p*100) write(chx,'(i0)') nx write(chy,'(i0)') ny fileName = prefix// & & "_p"//trim(chp)// "_x"//trim(chx)// "_y"//trim(chy)// & & ".txt" open(11,file=fileName,status='new')とすれば、例えば『prefix="percolation", p=0.5, nx=10, ny=20』のとき
"percolation_p050_x10_y20.txt"
というファイル名が自動的に生成されます。データの管理が格段に楽になるはずです。
上の例にあるように、実数型変数も整数型に変換(int)してから格納すると良い。
「パラメータが多くてファイル名が長すぎる!」という場合は、保存先ディレクトリのパスを自動生成すると良いでしょう。また、open文の「上書き禁止」(status='new')オプションと組み合わせることで、より安全な運用が可能です。
フォーマットに変数を使う(その2)
write文のフォーマットは文字列なので、この仕組みを使うことでも動的変更が可能です。前述の方法は簡単だがifort限定機能。この方法は少し面倒だが標準機能の範囲で可能。
たとえば、
FMT(1:9) = '(es??.??)' if(abs(value) < cutoff) then write(UNIT,'(i2)',advance='no') 0 else if(value<0) then write(FMT(4:5),'(i2)') d+8 else write(FMT(4:5),'(i2)') d+7 end if write(FMT(7:8),'(i2)') d write(UNIT,FMT,advance='no') value end if
フォーマットの途中にスペースが入っても大丈夫。
とすれば、valueがcutoff以下の時は「 0」、そうでなくても無駄な空白を省くよう出力する。出力ファイルがディスク容量を圧迫するようなら、1桁でも少なくするよう心がけるべきです。