Aggiunta a un ObjectOutputStream

Non è ansible aggiungere a un ObjectOutputStream ?

Sto cercando di aggiungere una lista di oggetti. Lo snippet seguente è una funzione che viene chiamata ogni volta che un lavoro è terminato.

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

Ma quando provo a leggerlo, ottengo solo il primo nel file. Quindi ricevo java.io.StreamCorruptedException .

Per leggere sto usando

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

Non so quanti oggetti saranno presenti, quindi sto leggendo mentre non ci sono eccezioni. Da quello che Google dice che questo non è ansible. Mi stavo chiedendo se qualcuno conosce un modo?

Ecco il trucco: sottoclass ObjectOutputStream e sovrascrivi il metodo 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(); } } 

Per usarlo, basta controllare se il file di cronologia esiste o no e creare un’istanza di questo stream appendibile (nel caso in cui il file esista = aggiungiamo = non vogliamo un’intestazione) o il stream originale (nel caso il file non esista = abbiamo bisogno di un colpo di testa).

modificare

Non ero contento della prima nomina della class. Questo è meglio: descrive “per cosa serve” piuttosto che “come è fatto”

modificare

Cambiato il nome ancora una volta, per chiarire, che questo stream è solo per l’accodamento a un file esistente. Non può essere utilizzato per creare un nuovo file con dati object.

modificare

Aggiunta una chiamata a reset() dopo che questa domanda ha mostrato che la versione originale che sovrascriveva writeStreamHeader come no-op poteva in alcune condizioni creare un stream che non poteva essere letto.

Come dice l’ API , il costruttore ObjectOutputStream scrive l’intestazione del stream di serializzazione nel stream sottostante. E questa intestazione dovrebbe essere una sola volta, all’inizio del file. Quindi chiamare

 new ObjectOutputStream(fos); 

più volte su FileOutputStream che fa riferimento allo stesso file, l’intestazione verrà scritta più volte e corrotto il file.

A causa del preciso formato del file serializzato, l’aggiunta lo corromperà. Devi scrivere tutti gli oggetti sul file come parte dello stesso stream, altrimenti si bloccherà quando leggerà i metadati dello stream quando è in attesa di un object.

Potresti leggere le Specifiche di serializzazione per maggiori dettagli, o (più semplice) leggere questo thread dove Roedy Green dice sostanzialmente quello che ho appena detto.

Il modo più semplice per evitare questo problema è mantenere l’OutputStream aperto quando si scrivono i dati, invece di chiuderli dopo ogni object. Chiamare reset() potrebbe essere consigliabile per evitare perdite di memoria.

L’alternativa sarebbe quella di leggere il file come una serie di ObjectInputStreams consecutivi. Ma questo richiede di tenere il conto di quanti byte si leggono (questo può essere implementato con un FilterInputStream), quindi chiudere InputStream, aprirlo di nuovo, saltare quel numero di byte e solo dopo avvolgerlo in un object ObjectInputStream ().

Che ne dici di ogni volta che aggiungi un object, leggi e copi tutti i dati correnti nel file e poi sovrascrivi tutti insieme per file.