Android開発でファイルの入出力を直接書くことはほぼないと思います。ただ、それ故に、あまり認知が進んでいないところかな?と思い立ったので書きます。
何らかの状態を保存する場合、特定のファイルに書き出し、次の更新ではそのファイルを上書き更新するということはよく行われます。
そこで、以下のように保存ファイルの書き換えを行うと、ファイルが破損してしまう可能性があります。
fun saveToFile() {
val file = File("/path/to/savefile")
file.outputStream().use { stream ->
// 書き込み処理
}
}
ファイルの上書きは、簡単に言えば
- 既存のファイルを削除し
- 書き込む内容を順次書き込んでいく
という処理になります。
書き換え中に何らかの問題が発生し、以下のような事態が発生した場合、
- 処理中のExceptionで処理を抜ける
- アプリのプロセスがKillされてしまう
- OSがハングアップする
- 端末の電源が切れる
書き換え前のデータは削除されていて、書き換え途中の読み出し不可能なデータが残ってしまったりします。
もちろんアプリ側で何をどう頑張っても回避できないファイル破損はありますが、アプリ側の工夫で回避できる部分は回避しましょう。
安全にファイルを上書きする場合は以下のようにします
fun saveToFile() {
val file = File("/path/to/savefile")
val tempFile = File(file.absolutePath + ".tmp")
tempFile.outputStream().use { stream ->
// 書き込み処理
}
Files.move(tempFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING)
保存したいファイル名で書き込むのではなく、別の名前のファイルとして書き出しを行い、完了したら、保存したいファイル名にリネームを行います。こうすることで
- リネーム完了していれば、更新後のファイル
- リネーム完了前は、更新前のファイル
が残ります。
書き換え途中の破損したファイルになってしまうことを防ぐことができます。