Android(Java)ではext4/fsync状況不明
-
11-10-2019 - |
質問
ティム・ブレイの記事 「安全にデータを保存する」 未解決の質問をしてくれました。今日、それは1か月以上であり、私はそれについてのフォローアップを見たことがないので、私はここでトピックに対処することにしました。
記事の1つのポイントは、FileOutputStreamを使用するときに安全な側にいるようにfiledeScriptor.sync()を呼び出す必要があることです。最初は非常にイライラしていました。なぜなら、私がJavaをする12年間にJavaコードが同期しているのを見たことがないからです。特にファイルへの対処はかなり基本的なことです。また、FileOutputStreamの標準Javadocは、同期を示唆していません(Java 1.0-6)。いくつかの調査の後、私はExt4が実際に同期を必要とする最初の主流ファイルシステムである可能性があると考えました。 (明示的な同期が推奨される他のファイルシステムはありますか?)
私はこの問題に関するいくつかの一般的な考えに感謝していますが、いくつかの具体的な質問もあります。
- Androidはいつファイルシステムに同期しますか?これは定期的であり、さらにライフサイクルイベントに基づいている可能性があります(たとえば、アプリのプロセスが背景に移動します)。
- filedeScriptor.sync()はメタデータの同期を処理しますか?これは、変更されたファイルのディレクトリを同期することです。 filechannel.force()と比較してください。
- 通常、FileOutputStreamに直接書き込むことはありません。これが私の解決策です(同意しますか?):
FileOutputStream fileOut = ctx.openFileOutput(file, Context.MODE_PRIVATE); BufferedOutputStream out = new BufferedOutputStream(fileOut); try { out.write(something); out.flush(); fileOut.getFD().sync(); } finally { out.close(); }
解決
Androidは、必要なときに同期を実行します - 画面がオフになったとき、デバイスのシャットダウンなど。「通常」操作を検討している場合は、アプリケーションによる明示的な同期は必要ありません。
問題は、ユーザーがデバイスからバッテリーを引き出し(またはカーネルのハードリセットを実行する)、データを失わないようにするときに発生します。
したがって、最初に実現することは、問題は電力が突然失われたときであるため、きれいなシャットダウンが起こることができず、その時点での永続的なストレージで何が起こるかという問題です。
単一の独立した新しいファイルを書いているだけである場合、それはあなたが何をするかは本当に関係ありません。ユーザーは、書き込みを開始する直前など、執筆中にバッテリーを引っ張った可能性があります。同期しない場合、バッテリーを引く間に書き込みが終わったときから長い時間があることを意味しますデータが失われます。
ここでの大きな懸念は、ファイルを更新する場合です。その場合、次にファイルを読んだとき また 前 コンテンツ、 また 新着 コンテンツ。中途半端なものを手に入れたり、データを失いたくありません。
これは、多くの場合、新しいファイルにデータを書き込み、古いファイルからそれに切り替えることによって行われます。 ext4の前に、ファイルの書き込みが終了したら、他のファイルでのさらなる操作がそのファイルのファイルになるまでディスク上に行かないため、前のファイルを安全に削除するか、新しいファイルに依存する操作を実行できます。完全に書かれている。
ただし、新しいファイルを書くと、古いファイルを削除してバッテリーが引かれます。次に起動すると、古いファイルが削除され、新しいファイルが作成されているが、新しいファイルの内容が完了していないことがわかります。同期を実行することにより、新しいファイルがその時点で完全に記述されていることを確認するため、その状態に依存するさらなる変更(古いファイルの削除など)を実行できます。
他のヒント
fileOut.getFD().sync();
前に、最終的に句に載るべきです close()
.
sync()
よりもはるかに重要です close()
耐久性を検討します。
だから、あなたがファイルで作業することを「終了」したいたびにあなたはすべきです sync()
前に close()
それをする。
Posixは、あなたが発行したときに保留中の書き込みがディスクに書き込まれることを保証しません close()
.