ファイルの存在確認と削除
消したはずのファイルを、もう一度消して落ちる
一時ファイルを片付ける処理を 2 回通ったり、前回の実行ですでに消えていたり。Files.delete は対象が無いと NoSuchFileException を投げるので、こういう場面であっさり止まります。「無ければ何もしなくていい」だけの処理なのに、例外が飛んでくるのは大げさに感じます。
ファイルの有無を調べるのは Files.exists です。Path を渡すと boolean が返ります。
Java
import java.nio.file.Files;
import java.nio.file.Path;
public class Demo {
public static void main(String[] args) throws Exception {
Path p = Path.of("work.tmp");
System.out.println(Files.exists(p)); // false
Files.createFile(p);
System.out.println(Files.exists(p)); // true
}
}Files.createFile は空のファイルを作ります。こちらは逆に、すでに同じ名前があると FileAlreadyExistsException になります。作成も削除も、失敗しうる操作なので IOException の仲間を投げます。
先に exists で確かめても、確実にはならない
では if (Files.exists(p)) で囲めば安全かというと、実はそうとも言い切れません。exists が true を返した直後に、別のプロセスがそのファイルを消してしまえば、続く Files.delete はやはり失敗します。確認した時点と使う時点がずれることによる、古くから知られた問題です。
「無ければ無いでいい」だけなら、確認と削除を 1 つにまとめた Files.deleteIfExists を使うのが確実です。消せたら true、もともと無ければ false を返し、どちらでも例外は投げません。
Files.delete(p)— 必ずあるはずのものを消す。無ければ例外で気づけるFiles.deleteIfExists(p)— 後片付け。無ければ静かにfalse
Java
Path p = Path.of("work.tmp");
System.out.println(Files.deleteIfExists(p)); // true (消せた)
System.out.println(Files.deleteIfExists(p)); // false (もう無い)どちらを使うかは、「そこに無いのは異常か、想定内か」で決めます。異常なら例外で止まったほうが原因に早くたどり着けます。
中身の残ったディレクトリは消せない
Files.delete はディレクトリにも使えますが、消せるのは空のときだけです。中にファイルが 1 つでも残っていれば DirectoryNotEmptyException になります。丸ごと消したいときは、Files.walk でたどってから深い側のものを先に削除する、という手順を自分で組みます。
削除は取り消せません。
Files.deleteは OS の API をそのまま呼ぶので、ゴミ箱にも入らずに消えます。パスを組み立てて削除するコードを書くときは、まず消す予定のパスを出力するだけのモードを作り、目で確かめてから本番に回してください。
やってみよう
Solution.createAndCheck() を完成させます。引数はありません。
- メソッドに
throws Exceptionを付ける - 一時ファイルを作り、作った直後に存在するかどうかを
booleanとして受け取る - そのファイルを削除する
- 削除後にもう一度確認し、「消えていること」を
booleanとして受け取る - 2 つの結果から
"created=true,deleted=true"の形の文字列を組み立ててreturnする
引っかかりやすいのは手順 4 です。削除後の Files.exists は false を返しますが、返したいのは「削除できたか」なので、その結果を反転させた値を使います。カンマの前後に余分な空白を入れないよう気をつけてください。
要件
Files.createTempFile(もしくはFiles.createFile+Paths.get) で一時ファイルを作ることFiles.exists(p)を 2 回呼び、作った直後はtrue、Files.delete(p)後はfalseになることを確認すること- 最終的に
"created=true,deleted=true"という形式の文字列をreturnすること
入出力例
createAndCheck() → "created=true,deleted=true"