概要
close
文にstatus="delete"
を指定することで,開いたファイルを閉じると同時に削除できます.
テスト環境
- Windows
- Windows 10
- gfortran 10.3.0
- intel fortran classic 2021.5.0
- nag fortran 7.1
- Linux
- Ubuntu 20.04
- gfortran 9.4.0
- intel fortran classic 2021.4.0
ファイルの削除
プログラムの実行中にファイルを削除したいという要望は,色々な場面で生じます.例えば,プログラム実行中に作成した一時的なファイルをプログラム終了時に削除したい,といった場面です.OSのシステムコマンドを実行するsystem
手続も存在しますが,OSによってコマンドやオプションが異なると,移植性のあるプログラムの作成が難しくなります.
! gfortran
integer(int32) :: stat
call system("del ファイル名", status=stat) ! Windows用
! call system("rm ファイル名", status=stat) ! Linux用
また,system
手続はFortran標準ではなく,コンパイラによって書き方が異なります.gfortranとNAG Fortranはsystem
サブルーチン,Intel Fortran classic (ifort)の場合はsystem
関数です1.
! NAG Fortran
use :: f90_unix_proc
implicit none
integer(int32) :: stat
call system("del ファイル名", status=stat)
! Intel Fortran classic
use :: ifport
implicit none
integer(int32) :: result ! ifportモジュールの中でstat手続が定義されており,変数名として使うと衝突する
result = system("del ファイル名")
このような事情から,ファイルを削除するには,system
手続ではなくFortranの標準機能で実現することを検討した方がよいでしょう.
Fortranでは,ファイルを開く際にopen
文,閉じる際にclose
文を用います.close
文のstatus
指定子に"delete"
を指定することで,読み取り専用でないファイルを削除できます.
program main
use, intrinsic :: iso_fortran_env
implicit none
integer(int32) :: unit_number, stat
open (newunit=unit_number, file=ファイル名, iostat=stat)
close (unit_number, status="delete", iostat=stat)
end program main
status
指定子には,もう一つ有効な値として"keep"
があります.これが指定されていると,ファイルを閉じる際にファイルを削除しません.status
が省略された場合は,status="keep"
が適用されます.
使用例
プログラム内で気軽に一時ファイルが削除できるようになりました.個人的には,この機能を知ったことで,ファイル出力を伴う手続のテストがやりやすくなったように感じます.
テストを行うことを考えると,ファイル出力の成否を確認する方法としては,ファイル出力を行った後にファイルが存在するかを確認することが最も簡単です.しかし,以前のテスト結果が残っていると,ファイル出力に成功した結果上書きされたファイルなのか,ファイル出力に失敗したのかがすぐには判りません.
また,バージョン管理ツールを使っていると,テストを実行した後に一時ファイルが残される場合に一時ファイルを追跡しないよう設定する必要があります.一時ファイルは追跡したくないけど,同じ拡張子を持つ他のファイルは追跡するといった設定が必要になる場合もあるでしょう.追跡しない(Untrackedのまま放置する)と,リポジトリのブランチ切替が妨げられる場合もあります.
テストを行うことで煩わしい状況になる(一時ファイルが大量に作られる,バージョン管理ツールの追加の設定が必要になる等)と,その煩わしい状況を避けるためにテストを実行しなくなってしまいます.これでは本末転倒です.プログラム内で気軽に一時ファイルが削除できるなら,活用した方がよいでしょう.
例えば,ファイル出力を伴う手続のテストを下記のような手順で行うと,一時ファイルを残さずにテストを完了できます.
program main
use, intrinsic :: iso_fortran_env
implicit none
character(:), allocatable :: name
integer(int32) :: stat, unit
name = 出力されるファイルの名前を設定する
! 1. 古いファイルが存在しているかを確認し,存在していれば削除する.
! 存在しているのに開けない場合,開けたが削除できない場合はテストが失敗したとする.
block
logical :: old_file_exists
inquire (file=name, exist=old_file_exists)
if (old_file_exists) then
! 削除するために開く.
open (newunit=unit, file=name, status="old", iostat=stat)
if (stat == 0) then
! open時にエラーがなければcloseする.
close (unit, status="delete", iostat=stat)
end if
else
stat = 0
end if
if (stat /= 0) error stop "test failed"
end block
! 2. ファイル出力を伴う処理を実行する.
! 3. 出力されたファイルを開く.
! 開けない場合はテストが失敗したとする.
open (newunit=unit, file=name, status="old", action="read", position="rewind", iostat=stat)
if (stat /= 0) error stop "test failed"
! 4. ファイルの中が想定通りの結果になっているかを調べる.
! 想定通りでない場合はテストが失敗したとする.
! 5. ファイルを削除する.
! 削除できなかった場合はテストが失敗したとする.
close (unit, status="delete", iostat=stat)
if (stat /= 0) error stop "test failed"
end program main
まとめ
close
文のstatus
指定子を利用することで,ファイルを閉じる際にファイルを削除することができます.
close
文は頻繁に使っていたのですが,status
指定子を持っていることを把握していませんでした.使い慣れた処理であっても,調べてみると新しい発見がありますね.
-
ifortであっても,実行の成否を取得しないのであれば,
system
サブルーチンが利用できます. ↩