61

に追加することはできませんObjectOutputStreamか?

オブジェクトのリストに追加しようとしています。次のスニペットは、ジョブが終了するたびに呼び出される関数です。

FileOutputStream fos = new FileOutputStream
           (preferences.getAppDataLocation() + "history" , true);
ObjectOutputStream out = new ObjectOutputStream(fos);

out.writeObject( new Stuff(stuff) );
out.close();

しかし、それを読み取ろうとすると、ファイルの最初のものしか取得できません。それから私は得るjava.io.StreamCorruptedException

私が使用していることを読むために

FileInputStream fis = new FileInputStream
        ( preferences.getAppDataLocation() + "history");
ObjectInputStream in = new ObjectInputStream(fis);    

try{
    while(true)
        history.add((Stuff) in.readObject());
}catch( Exception e ) { 
    System.out.println( e.toString() );
}

オブジェクトがいくつ存在するか分からないので、例外がないうちに読んでいます。Googleが言っていることから、これは不可能です。誰かが方法を知っているかどうか疑問に思っていましたか?

4

6 に答える 6

81

秘訣は次のとおりです。メソッドをサブクラス化ObjectOutputStreamしてオーバーライドしますwriteStreamHeader

public class AppendingObjectOutputStream extends ObjectOutputStream {

  public AppendingObjectOutputStream(OutputStream out) throws IOException {
    super(out);
  }

  @Override
  protected void writeStreamHeader() throws IOException {
    // do not write a header, but reset:
    // this line added after another question
    // showed a problem with the original
    reset();
  }

}

これを使用するには、履歴ファイルが存在するかどうかを確認し、この追加可能なストリーム(ファイルが存在する場合=追加=ヘッダーが不要)または元のストリーム(ファイルが存在しない場合=)のいずれかをインスタンス化します。ヘッダーが必要です)。

編集

クラスの最初の命名に満足していませんでした。これはより良いです:それは「それがどのように行われるか」ではなく「それが何のためにあるのか」を説明します

編集

このストリームは既存のファイルに追加するためだけのものであることを明確にするために、名前をもう一度変更しました。オブジェクトデータを使用して新しいファイルを作成するために使用することはできません。

編集

この質問reset()の後にへの呼び出しを追加しました。これは、操作が行われないように上書きされた元のバージョンが、特定の条件下で読み取りできないストリームを作成する可能性があることを示しました。writeStreamHeader

于 2009-07-28T15:58:06.743 に答える
16

APIが示すように、ObjectOutputStreamコンストラクターはシリアライゼーション ストリーム ヘッダーを基になるストリームに書き込みます。また、このヘッダーは、ファイルの先頭に 1 回だけ存在すると予想されます。そう呼ぶ

new ObjectOutputStream(fos);

で同じファイルを複数回FileOutputStream参照すると、ヘッダーが複数回書き込まれ、ファイルが破損します。

于 2009-07-28T15:18:36.230 に答える
8

シリアル化されたファイルの正確な形式のため、追加すると実際にファイルが破損します。すべてのオブジェクトを同じストリームの一部としてファイルに書き込む必要があります。そうしないと、オブジェクトを期待しているときにストリーム メタデータを読み取るときにクラッシュします。

詳細についてはシリアライゼーション仕様を読むか、(より簡単に) Roedy Green が基本的に私が言ったことを言っているこのスレッドを読むことができます。

于 2009-07-28T15:13:46.393 に答える
7

この問題を回避する最も簡単な方法は、各オブジェクトの後に OutputStream を閉じるのではなく、データを書き込むときに OutputStream を開いたままにすることです。reset()メモリ リークを回避するには、呼び出しを行うことをお勧めします。

別の方法として、ファイルを一連の連続する ObjectInputStreams として読み取ることもできます。ただし、これには、読み取ったバイト数をカウントし続け (これは FilterInputStream で実装できます)、InputStream を閉じてから再度開き、そのバイト数をスキップしてから ObjectInputStream() でラップする必要があります。

于 2009-07-28T15:30:49.890 に答える
0

オブジェクトを追加するたびに、ファイル内の現在のすべてのデータを読み取ってコピーし、すべてをまとめてファイルに上書きする前にどうですか。

于 2014-11-09T22:12:01.187 に答える