2011-01-16 26 views
13

Tim Brayの記事"Saving Data Safely"は未解決の質問を残しました。今日は1ヵ月以上経過しており、フォローアップは見られませんでしたので、ここで話題に取り組むことにしました。Android(Java)のext4/fsyncの状況が不明確

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(); 
    } 
    

答えて

10

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

問題は、ユーザーがデバイスからバッテリーを取り出したとき(またはカーネルをハードリセットしたとき)、データを失わないようにするためです。

まず、電源が突然失われてしまい、クリーンなシャットダウンができなくなること、そしてその時点で永続的なストレージに何が起こるのかという問題を認識することです。

あなたがただ1つの独立した新しいファイルを書いているのであれば、あなたがしていることは本当に問題ではありません。あなたが書き込みの途中だったとき、書き込みを始める前などにバッテリーを引っ張ってしまった可能性があります。同期していないと、書き込みを終えてからバッテリーを引き出すのに長い時間がかかるだけですデータが失われます。

大きな懸念は、ファイルを更新する場合です。あなたは次のファイルを読み込むときにその場合、あなたはどちらか以前内容、または新しい内容を持っていると思います。途中で何かを書いたり、データを失いたくないのです。

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

ただし、新しいファイルを書き込み、古いファイルを削除してバッテリを取り出すと、次回の起動時に古いファイルが削除され、新しいファイルが作成されても新しいファイルの内容が表示されることがあります完了しません。同期を行うことで、新しいファイルがその時点で完全に書き込まれていることを確認し、その状態に依存する追加の変更(古いファイルの削除など)を行うことができます。

+0

私はflush()がすべてがディスクに書き込まれていることを確認することを期待していました - 本質的にsync()を呼び出すことによって。そうじゃないの? –

+0

@a_horse_with_no_name:いいえ、そうではありません。 _flush_と_sync_は、2つの異なる操作です:フラッシュは単に中間バッファをフラッシュします。 syncは実際にストレージに書き込みます。例えば、 http://stackoverflow.com/questions/2340610/difference-between-fflush-and-fsync – sleske

+0

@sleske:明確化のおかげで! –

1

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

sync()は、耐久性を考慮してclose()より重要です。

だから、ファイルを処理することを「完了」したいときは、sync()より前にclose()とする必要があります。

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

関連する問題