を追加するObjectOutputStream
-
19-09-2019 - |
質問
できないのですか追加する 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ということはできません。破壊も修復もおもしろくな誰でも知っている。
解決
ここでのトリックです:サブクラス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();
}
}
ちょうど履歴ファイルが存在するかどうかをチェックし、ファイルがない場合には、この追記ストリーム(場合にファイルが存在する=私たちは=私たちは、ヘッダーをしたくない追加)または元のストリーム(いずれかをインスタンス化し、それを使用するには=我々はヘッダが必要)が存在しない。
編集
私は、クラスの最初の命名と幸せではなかったです。この1のより良い:それはそれがために何を "というし、「どのように行うの」
説明編集
このストリームは、既存のファイルに追加するためのものであることを、明確にするために、もう一度名前を変更しました。オブジェクトデータとの新しいのファイルを作成するために使用することはできません。
編集
は、後のがあることを示したこの質問をreset()
するための呼び出しを追加しました無操作できなくするだけオーバーライドwriteStreamHeader
は、いくつかの条件の下で読み取ることができませんでしたストリームを作成することができ、元のバージョンます。
他のヒント
としての API のとおり、 ObjectOutputStream
コンストラクタに書き込み、直列化ストリームヘッダの基本となるストリームです。このヘッダは一度だけの初めにファイルです。で呼び出し
new ObjectOutputStream(fos);
複数回の FileOutputStream
名とパスワードを送信すればよい同一ファイルのヘッダに複数回のや腐敗のファイルです。
ので、シリアライズされたファイルの正確な形式の、追加それ確かに壊れています。あなたは、同じストリームの一部としてファイルにすべてのオブジェクトを記述する必要があり、またはそうでなければ、オブジェクトを期待していますとき、それはストリームメタデータを読み込むときにクラッシュします。
あなたは直列化仕様のrel="noreferrer">のこのスレッド Roedyグリーンは私がちょうど言ったことを基本的に言うところます。
この問題を回避する最も簡単な方法は、あなたがデータを書き込むとき、代わりに、各オブジェクトの後にそれを閉じる、開いたOutputStreamを維持することです。 reset()
を呼び出すと、メモリリークを避けることが賢明かもしれません。
の代替は、同様に連続しObjectInputStreams一連のファイルを読み込むことであろう。しかし、これは)あなたが読んでどのように多くのバイトを数える(これはFilterInputStreamでimplementdすることができます)、その後、InputStreamを閉じ、再度開いて、だけにして多くのバイトとはObjectInputStreamの(でそれをラップすることをスキップ維持する必要があります。
どの程度あなたがオブジェクトを追加するたびに前に、読んで、ファイル内のすべての現在のデータをコピーして、ファイルに一緒にすべて上書きします。
私は追加して、新しいファイルを作成し、両方のために使用することができるクラスを作成するために受け入れたソリューションを高めています。
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class AppendableObjectOutputStream extends ObjectOutputStream {
private boolean append;
private boolean initialized;
private DataOutputStream dout;
protected AppendableObjectOutputStream(boolean append) throws IOException, SecurityException {
super();
this.append = append;
this.initialized = true;
}
public AppendableObjectOutputStream(OutputStream out, boolean append) throws IOException {
super(out);
this.append = append;
this.initialized = true;
this.dout = new DataOutputStream(out);
this.writeStreamHeader();
}
@Override
protected void writeStreamHeader() throws IOException {
if (!this.initialized || this.append) return;
if (dout != null) {
dout.writeShort(STREAM_MAGIC);
dout.writeShort(STREAM_VERSION);
}
}
}
このクラスはObjectOutputStreamのための直接的な拡張代替として使用することができます。 次のように私たちは、クラスを使用することができます:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ObjectWriter {
public static void main(String[] args) {
File file = new File("file.dat");
boolean append = file.exists(); // if file exists then append, otherwise create new
try (
FileOutputStream fout = new FileOutputStream(file, append);
AppendableObjectOutputStream oout = new AppendableObjectOutputStream(fout, append);
) {
oout.writeObject(...); // replace "..." with serializable object to be written
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}