prasinos' work memo

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ファイル末尾へのシーク(2)

OPEN 文による位置づけができるなんて書いたが、世の中そんなに甘くない。
どうもファイルを開くときにしかやってはいけないみたいだ。
したがって、次のようにファイルを閉じて開かないといけない。

program eof
open(10, file='test.dat', form='unformatted', access='sequential')
rewind(10)
write(10) 'INIT'
write(10) 'MID '
write(10) 'END '
rewind(10)
print *, 'rewind'
call list(10)
print *, 'seek to EOF - 1'
close(10)
open(10, file='test.dat', form='unformatted', access='sequential', position='append')
backspace(10)
call list(10)
print *, 'seek to EOF - 2'
backspace(10)
close(10)
open(10, file='test.dat', form='unformatted', access='sequential', position='append')
backspace(10)
backspace(10)
call list(10)
close(10, status='DELETE')
contains
subroutine list(ifile)
integer:: iostat
character(4):: str
print *, '--- list ---'
do
read(ifile, iostat=iostat) str
if (iostat /= 0) exit
print *, '[', str, ']'
enddo
print *, 'iostat=', iostat
end subroutine
end program

スポンサーサイト

ファイル末尾へのシーク

Fortran のシーケンシャルファイルでは、WRITE 文を実行するとその後のレコードが消えてしまうことになっている。規則は規則で、ばかげていると文句をいってもはじまらないので、ファイルの内容の一部がアップデートされるようなファイルを管理するときは、変更されやすいものを最後に持ってくることになる。そうすると、レコードを次々追加していくような状況を想定すると、レコードの一覧表みたいなものは当然最後の最後に書かれなければならない。

ところがファイルを読む立場からすると、レコードの一覧表なんかは真っ先に読みたいものであるわけで、ファイルを開いたら即座に末尾にシークしなければならないわけである。そこでどうやってシークするかが問題なのであるが、 FORTRAN77 では

10000 CONTINUE
00000 READ(IUNIT, IOSTAT=IOSTAT)
00000 IF (IOSTAT .NE. 0) GOTO 10001
00000 GOTO 10000
10001 CONTINUE


といった感じで全レコードをひたすら読み飛ばさないといけなかった。

さすがにこれでは速度的にどうよというわけで、Fortran 90 で何か使えそうなものがないかと探してみると、OPEN 文で位置づけができるらしい。プログラム例はこんなんである。

program eof
open(10, file='test.dat', form='unformatted', access='sequential')
write(10) 'INIT'
write(10) 'MID '
write(10) 'END '
rewind(10)
open(10, position='REWIND')
print *, 'rewind'
call list(10)
print *, 'seek to EOF - 1'
rewind(10)
open(10, position='APPEND')
backspace(10)
call list(10)
print *, 'seek to EOF - 2'
rewind(10)
open(10, position='APPEND')
backspace(10)
backspace(10)
call list(10)
close(10, status='DELETE')
contains
subroutine list(ifile)
integer:: iostat
character(4):: str
print *, '--- list ---'
do
read(ifile, iostat=iostat) str
if (iostat /= 0) exit
print *, '[', str, ']'
enddo
print *, 'iostat=', iostat
end subroutine
end program


9月23日版の g95 で動いたから多分大丈夫だろう。
[追記] やっぱり可搬性の問題あり


注意点としては、いったん end-of-file condition に陥ってしまったファイルはどうやら BACKSPACE 文か REWIND 文でないとこのエラーをクリアできないらしいということである。本当かなあ。規格本文をあたらないと。

ところで、何ギガバイトもある巨大なファイルをシークすると悪いことが起こらないだろうか。いや、どうせカーネルのなかでオフセット番号書き換えるだけだから、きっと何も悪いことは起こらないに違いない...。

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。