Files でファイルに書き込む
書いたはずのファイルが、開いたら空だった
FileWriter に文字列を渡して write を呼び、プログラムを終わらせて、できたファイルを開いたら中身が空。ファイル書き込みで最初に出会うのがこれです。書いた内容はいったん手元にため込まれ、close() を呼んだ時点で初めてディスクへ流れるので、閉じ忘れた分がまるごと消えます。
いまの Java なら、この手順ごと java.nio.file.Files に任せられます。writeString は、開く、書く、閉じるまでを 1 行の中で終わらせてくれます。
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("memo.txt");
Files.writeString(p, "今日の作業メモ");
}
}Path は「どのファイルか」を表す型です。読み返すときは対になる Files.readString(p) を呼べば、中身がまるごと String で返ってきます。どちらも失敗しうる操作なので IOException を投げます。throws を付けるか try で受けるかは、これまでの例外処理の回と同じ判断です。
保存先を決め打ちにすると、2 人同時に走った瞬間に壊れる
Path.of("memo.txt") のように名前を固定すると、同じ処理が同時に 2 つ動いたときに同じファイルを奪い合います。テストを並列で回した途端に落ちるのは、たいていこれが原因です。
一時的な置き場が欲しいだけなら Files.createTempFile を使います。OS の一時ディレクトリに、他とぶつからない名前でファイルを作り、その Path を返してくれます。
Java
Path tmp = Files.createTempFile("report", ".csv");
System.out.println(tmp); // 例 /tmp/report8471250.csv
Files.delete(tmp); // 使い終わったら消す第 1 引数が名前の先頭、第 2 引数が拡張子で、その間に重複しない文字列が入ります。作りっぱなしにすると一時ディレクトリにごみがたまるので、Files.delete で片付けるところまでを一組と考えてください。
Windows で書いたファイルが、Linux で文字化けする
古い FileWriter は、動いている環境の既定の文字コードで書き出します。Windows で作ったファイルには Shift_JIS が、Linux では UTF-8 が使われるので、日本語を含むファイルを受け渡した瞬間に化けます。
Files.writeString と Files.readString は、指定しない限り常に UTF-8 です。環境が変わっても結果は変わりません。別の文字コードで書かれた古いファイルを読む必要があるときだけ、Charset を追加の引数で渡します。
追記したいのに上書きになってしまう、というのもよくある落とし穴です。
Files.writeStringは既定で中身を丸ごと置き換えます。末尾に足したいときはStandardOpenOption.APPENDを第 3 引数に渡してください。
やってみよう
Solution.writeAndRead(String content) を完成させます。
throws Exceptionを付けるか、内部でtryを使ってIOExceptionを扱えるようにするFiles.createTempFileで一時ファイルを作る。パスの決め打ちは禁止です- 受け取った
contentをその一時ファイルに書き込む - 同じファイルを読み返した文字列を
returnする - 後始末として一時ファイルを削除する
テストは空文字列と英字と日本語の 3 つで、書いた文字列がそのまま返るかを見ています。文字コードを自分で指定しなくても日本語が往復することを、"日本語" のケースで確かめてください。
要件
java.nio.file.Files.createTempFileを使って一時ファイルを作成すること (パスのハードコードは禁止)Files.writeString(path, content)で書き込み、Files.readString(path)で読み返した値をreturnすることthrows Exceptionかtry-catchでIOExceptionを適切に扱うこと
入出力例
writeAndRead("hello") → "hello"
writeAndRead("") → ""
writeAndRead("日本語") → "日本語"
writeAndRead("line1
line2") → "line1
line2"