13

Tim Bray の記事"Saving Data Safely"は未解決の問題を残しました。今日、それは 1 か月以上経ちましたが、フォローアップが見られなかったので、ここでトピックを扱うことにしました。

この記事のポイントの 1 つは、FileOutputStream を使用する場合、安全のために FileDescriptor.sync() を呼び出す必要があることです。Java を 12 年間やっている間、Java コードが同期しているのを見たことがなかったので、最初はとてもイライラしました。特に、ファイルへの対処はかなり基本的なことです。また、FileOutputStream の標準 JavaDoc は、同期をほのめかしませんでした (Java 1.0 - 6)。いくつかの調査の結果、ext4 が実際に同期を必要とする最初のメインストリーム ファイル システムである可能性があることがわかりました。(明示的な同期が推奨される他のファイル システムはありますか?)

この件についての一般的な考えに感謝しますが、具体的な質問もいくつかあります。

  1. Android はいつファイル システムと同期しますか? これは定期的であり、さらにライフ サイクル イベントに基づいている場合もあります (たとえば、アプリのプロセスがバックグラウンドに移行するなど)。
  2. FileDescriptor.sync() はメタデータの同期を処理しますか? つまり、変更されたファイルのディレクトリを同期しています。FileChannel.force() と比較してください。
  3. 通常、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();
    }
    
4

2 に答える 2

10

Android は、画面がオフになったとき、デバイスをシャットダウンしたときなど、必要なときに同期を行います。「通常の」操作だけを見ている場合は、アプリケーションによる明示的な同期は必要ありません。

問題は、ユーザーがデバイスからバッテリーを抜いた (またはカーネルのハード リセットを行った) ときに発生し、データを失わないようにしたい場合です。

したがって、最初に認識すべきこと: 問題は、電源が突然失われた場合であり、そのため、クリーン シャットダウンを行うことができず、その時点で永続ストレージで何が起こるかという問題です。

単一の独立した新しいファイルを作成するだけであれば、何をするかは問題ではありません。書き込みの途中、書き込みを開始する直前などに、ユーザーがバッテリーを抜いた可能性があります。同期しない場合は、書き込みが完了してからバッテリーを抜くまでの時間が長いことを意味します。データが失われます。

ここでの大きな懸念は、ファイルを更新する場合です。その場合、次にファイルを読み取るときに、以前の内容または新しい内容のいずれかが必要です。途中で何かを書き込んだり、データを失ったりしたくはありません。

これは多くの場合、新しいファイルにデータを書き込んでから、古いファイルからそのデータに切り替えることによって行われます。ext4 より前は、ファイルの書き込みが完了すると、他のファイルに対する操作は、そのファイルに対する操作が行われるまでディスクに反映されないことがわかっていたので、以前のファイルを安全に削除したり、新しいファイルに依存する操作を行ったりすることができました。完全に書かれています。

ただし、新しいファイルを書き込んでから古いファイルを削除し、バッテリーを抜いた場合、次回の起動時に、古いファイルが削除され、新しいファイルが作成されていることがわかりますが、新しいファイルの内容は完全ではありません。同期を行うことで、その時点で新しいファイルが完全に書き込まれ、その状態に応じてさらに変更 (古いファイルの削除など) を実行できるようになります。

于 2011-01-16T22:15:18.453 に答える
1

fileOut.getFD().sync();の前のfinally句にある必要がありclose()ます。

sync()close()耐久性よりも重要です。

したがって、ファイルの作業を「終了」したいときはいつでも、ファイルをing するsync()前に終了する必要があります。close()

posix は、 を発行したときに保留中の書き込みがディスクに書き込まれることを保証しませんclose()

于 2011-11-18T20:11:05.527 に答える