1
votes

Sérialisable sur ArrayList perd des données

J'ai une ArrayList d'objets Employee où la classe Employee implémente Serializable. J'utilise ce code pour écrire des listes dans un fichier:

ArrayList<Employee> empList = new ArrayList<>();
  FileOutputStream fos = new FileOutputStream("EmpObject.ser");
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  // write object to file
  empList .add(emp1);
  empList .add(emp2);
  empList .add(emp3);
  oos.writeObject(empList);
}

Si j'essaye de le dé-sérialiser, je reçois juste les deux premiers objets et non le 3ème. Quelqu'un peut-il essayer pourquoi?

edit1: Si j'ajoute tous les éléments en même temps, tout va bien mais pas comme je l'ai fait au début. Quelle est la différence?

ArrayList<Employee> empList = new ArrayList<>();
  FileOutputStream fos = new FileOutputStream("EmpObject.ser");
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  // write object to file
  empList .add(emp1);
  empList .add(emp2);
  oos.writeObject(empList);

  empList .add(emp3);

  oos.writeObject(empList);
}

Après cela, j'ai 3 éléments


0 commentaires

3 Réponses :


2
votes

Que se passe-t-il avec votre code:

  • vous écrivez la liste dans le fichier, avec deux entrées
  • vous avez réinitialisé le flux
  • vous réécrivez la liste, avec trois entrées

Ainsi, votre fichier contient deux valeurs, oui. Deux listes, une avec 2, une avec 3 entrées.

En d'autres termes: reset () ne réinitialise pas ce qui a été écrit dans le fichier! Vous avez rédigé une liste avec deux entrées. Vous êtes uniquement en train de réinitialiser les informations sur les objets stockés, de sorte que emp1 et emp2 soient à nouveau sérialisés . Sans l'appel de réinitialisation, la JVM comprendrait qu'elle n'a pas besoin de sérialiser à nouveau complètement emp1 et emp2. ​​

Signification: par défaut, la JVM compresse la quantité de données à transmettre. Il se souvient des objets déjà écrits et au lieu de les écrire à plusieurs reprises, il écrit seulement quelque chose comme "l'objet X qui a été sérialisé plus tôt revient" dans le flux.

Donc: je pense que vous ne comprenez tout simplement pas le but de la méthode reset () . Solution: lisez un petit tutoriel, comme celui de tutorialspoint .

Modifier compte tenu du dernier commentaire du PO:

Ce que vous demandez n'est pas possible de cette manière. Vous écrivez des objets de liste . Cela signifie que toutes les entrées de cette liste à ce stade sont écrites dans le fichier. La JVM se souvient que "cette liste a déjà été écrite", donc elle ne la réécrira pas , même si son état interne a changé entre-temps.


0 commentaires

1
votes

Fondamentalement, ObjectOutputStream se souvient des objets qui y sont écrits. Si le même objet (par référence) est réécrit, il n'est pas sérialisé, mais plutôt une référence aux données sérialisées précédentes est écrite dans le flux. La méthode reset () nettoie les structures de données internes de ObjectOutputStream et vous permet d'écrire à nouveau le même objet. reset () ne supprime pas les données déjà écrites dans le flux.

Si vous essayez de désérialiser votre flux en deux ArrayLists, vous en obtiendrez une avec deux éléments et une avec trois éléments.

Si vous supprimez l'appel à la méthode reset () , alors vous obtiendrez deux listes de tableaux avec deux éléments (un réellement sérialisé et un autre comme référence à l'instance sérialisée précédente)


5 commentaires

Les appels OP sont réinitialisés dans son premier exemple, et il dit que cela ne fonctionne toujours pas?


En fait, je ne veux pas réinitialiser (). Je veux juste un ArrayList avec 3 éléments, MAIS JE NE VEUX PAS ajouter tous les éléments de la liste à la fois. 2 premiers éléments puis un de plus.


Si vous voulez écrire ArrayList une fois, écrivez-le une fois. Vous ne pouvez pas écrire une liste Array avec deux éléments dans un fichier et vous attendre à en lire trois éléments. Vous pouvez créer un nouveau FileOutputStream et écraser les données déjà écrites, mais vous ne pouvez pas ajouter de nouvelles données au même flux et vous attendre à ce que les données précédemment écrites disparaissent d'une manière ou d'une autre.


oh donc il n'est pas possible de faire de cette façon alors Quelle est la meilleure façon d'écrire puis de la désérialiser


Merci beaucoup. Je comprends que ce que j'essayais de faire n'était pas possible. Merci



2
votes

Comme GhostCat et uaraven l'ont déjà mentionné, reset ne fait pas ce que vous attendez de lui et vous devriez jeter un œil à un tutoriel sur la sérialisation et peut-être envisager d'utiliser sth. sinon, si cela ne correspond pas à votre cas d'utilisation.

Votre code pourrait ressembler à ceci si vous créez un nouveau FileOutputStream:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class SerializationTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String path = "EmpObject.ser";

        ArrayList<Employee> empList = new ArrayList<>();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));

        empList.add(emp1);
        empList.add(emp2);
        oos.writeObject(empList);

        empList.add(emp3);
        // Create a new FileOutputStream to override the files content instead of appending the new employee list
        oos = new ObjectOutputStream( new FileOutputStream(path));
        oos.writeObject(empList);

        ObjectInputStream objectinputstream = new ObjectInputStream(new FileInputStream(path));
        List<Employee> readCase = (List<Employee>) objectinputstream.readObject();

        System.out.println(readCase);
    }
}


1 commentaires

Merci beaucoup à tous. J'ai suivi le didacticiel. Je l'ai maintenant. Juste besoin de créer un nouveau flux de sortie comme mentionné par @FlorianDe. Merci beaucoup pour l'aide