60 votes

Ajout à un ObjectOutputStream

Il n'est pas possible d'ajouter à un ObjectOutputStream?

Je suis en train d'ajouter à une liste d'objets. L'extrait de code suivant est une fonction qui est appelée chaque fois qu'un travail est terminé.

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

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

Mais quand j'essaie de le lire, je seulement obtenir la première dans le fichier. Puis-je obtenir de l' java.io.StreamCorruptedException.

De lire, je suis en utilisant

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

Je ne sais pas combien d'objets sera présente donc, je suis à la lecture il n'y a pas d'exceptions. À partir de ce que Google dit que c'est pas possible. Je me demandais si quelqu'un connaît un moyen?

80voto

Andreas_D Points 64111

Voici l'astuce: sous-classe ObjectOutputStream et remplacer l' writeStreamHeader méthode:

public class AppendingObjectOutputStream extends ObjectOutputStream {

  public AppendingObjectOutputStream(OutputStream out) {
    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();
  }

}

Pour l'utiliser, il suffit de vérifier si le fichier de l'historique existe ou pas et d'instancier cette appendable flux (dans le cas où le fichier n'existe pas = nous append = nous ne voulons pas d'un en-tête) ou le flux d'origine (dans le cas où le fichier n'existe pas = nous avons besoin d'un en-tête).

Modifier

Je n'étais pas heureux avec la première appellation de la classe. C'est la meilleure: il décrit le "pour quoi il est plutôt le "comment c'est fait"

Modifier

Changé le nom une fois de plus, de préciser que ce flux est uniquement pour permettre l'ajout d'un fichier existant. Il ne peut pas être utilisée pour créer un nouveau fichier avec les données de l'objet.

Modifier

Ajout d'un appel à l' reset() après cette question a montré que la version d'origine est simplement remplacé writeStreamHeader d'être un no-op pouvaient, dans certaines conditions, créer un flux qui n'a pas pu être lue.

14voto

Tadeusz Kopec Points 7625

Comme l' API dit, l' ObjectOutputStream constructeur écrit la sérialisation en-tête de flux pour le flux sous-jacent. Et cet en-tête devrait être qu'une seule fois, en début de fichier. Afin de l'appelant

new ObjectOutputStream(fos);

plusieurs fois sur l' FileOutputStream qui fait référence au même fichier va écrire l'en-tête plusieurs fois, et endommagé le fichier.

7voto

Michael Myers Points 82361

En raison de la forme précise du fichier sérialisé, ajoutant sera en effet la corrompre. Vous devez écrire tous les objets dans le fichier en tant que partie d'un même ensemble, ou bien il va se bloquer lorsqu'il lit le flux de métadonnées lorsqu'il s'attend à un objet.

Vous avez pu lire la Sérialisation des Spécifications pour plus de détails, ou (plus facile) lire ce fil où Roedy Green dit, fondamentalement, ce que je viens de dire.

7voto

Michael Borgwardt Points 181658

La façon la plus simple pour éviter ce problème est de garder le OutputStream ouvrir lorsque vous écrivez les données, au lieu de le fermer après chaque objet. Appelant reset() pourrait être souhaitable d'éviter les fuites de mémoire.

L'alternative serait de lire le fichier comme une série consécutive de ObjectInputStreams ainsi. Mais cela vous oblige à garder compter le nombre d'octets que vous avez lu (ce qui peut être implementd avec un FilterInputStream), puis fermez le InputStream, l'ouvrir à nouveau, ignorer que nombre d'octets, et seulement alors, l'envelopper dans un ObjectInputStream().

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X