Aller au contenu

Sérialisation binaire

La sérialisation de classes avec des objets Java permet de créer des fichiers binaires. Ceux-ci sont facilement transférables dans d'autres applications Java, mais difficilement portables dans d'autres langages.

Deux conditions doivent être remplies pour créer un objet binaire à partir de classes :

  • Les types de propriétés doivent être sérialisables
  • Les classes doivent implémenter l'interface Serializable
import java.io.Serializable;
import java.util.HashMap;

public class Etudiant implements Serializable {
    private String nom;
    private String prenom;
    private String noEtudiant;
    private HashMap<String, Float> notes;

    public Etudiant(String nom, String prenom, String noEtudiant) {...}

    public void ajouterNote(String cours, float note) {...}
}

Écriture vers un fichier

Pour écrire vers un fichier, on utilise un ObjectOutputStream et un FileOutputStream pour écrire l'objet vers un fichier binaire.

// Création d'un tableau d'étudiants
ArrayList<Etudiant> etudiants = new ArrayList<>(Arrays.asList(
        new Etudiant("Tremblay", "Jean", "123456"),
        new Etudiant("Gagnon", "Marie", "654321"),
        new Etudiant("Lavoie", "Pierre", "456789")
));

// Écriture vers un fichier
try {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("etudiants.bin"));
    oos.writeObject(etudiants);
    oos.close();
} catch (IOException e) {
    throw new RuntimeException(e);
}

Le fichier sera alors créé dans le dossier du projet.

Attention

Ne pas utiliser de classe anonyme pour créer les étudiants d'un coup, sinon la désérialisation ne fonctionnera pas comme prévu!

ArrayList<Etudiant> etudiants = new ArrayList<>() {
    {
        add(new Etudiant("Tremblay", "Jean", "123456"));
        add(new Etudiant("Gagnon", "Marie", "654321"));
        add(new Etudiant("Lavoie", "Pierre", "456789"));
    }
};

Lecture d'un fichier

Pour lire un fichier sérialisé binaire, on doit absolument connaître sa structure interne. Dans l'exemple ci-dessus, nous avons un ArrayList qui contient des instances de type Etudiant. De plus, chaque étudiant est constitué d'un nom, d'un prénom et d'un numéro étudiant, tous de type String, en plus d'un HashMap<String, Float>. Les classes doivent être identiques afin de pouvoir désérialiser un fichier, sans quoi des erreurs pourraient survenir.

// Désérialiser
ArrayList<Etudiant> etudiantsRecuperes;
try {
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("etudiants.bin"));
    etudiantsRecuperes = (ArrayList<Etudiant>) ois.readObject();
    for (Etudiant etudiant : etudiantsRecuperes) {
        System.out.println(etudiant);
    }
} catch (IOException | ClassNotFoundException e) {
    throw new RuntimeException(e);
}

// Afficher les étudiants
for (Etudiant etudiant : etudiantsRecuperes) {
    System.out.println(etudiant.getNom());
}

Le nom des étudiants sera alors affiché.

Problèmes de portabilité

La portabilité de ces types de fichiers n'est pas idéale. Un fichier sérialisé ressemble à ceci vu dans un éditeur de texte :

etudiants.bin
�� sr java.util.ArrayListx����a� I sizexp   w   sr Etudiant9V����& L 
noEtudiantt Ljava/lang/String;L nomq ~ L notest Ljava/util/HashMap;L prenomq ~ xpt 123456t Tremblaysr java.util.HashMap���`� F 
loadFactorI     thresholdxp?@     w      t INF3135sr java.lang.Float��ɢ�<�� F valuexr java.lang.Number������  xpB���t INF1130sq ~ B���t INF2120sq ~ B���t INF1120sq ~ Alt INF3143sq ~ B'!�xt Jeansq ~ t 654321t Gagnonsq ~ ?@     w      q ~ 
sq ~ B���q ~ sq ~ B��Uq ~ sq ~ BoVMq ~ sq ~ @�h�q ~ sq ~ B��Kxt Mariesq ~ t 456789t Lavoiesq ~ ?@     w      q ~ 
sq ~ B-v�q ~ sq ~ @��.q ~ sq ~ A���q ~ sq ~ B�s�q ~ sq ~ B�j�xt Pierrex

Il est très difficile de lire le contenu sans nécessairement connaître sa structure. De plus, il sera également difficile d'importer ce fichier dans un autre langage. Ces inconvénients diminuent grandement son utilité.