Site:  Cours VB.net  
5.8 Conservation des valeurs; sérialisation.

Quand un objet est détruit (fin de programme), les valeurs de ses attributs (les variables) sont perdues!!

Si les valeurs de l'objet changent et doivent être retrouvées lors d'une utilisation ultérieure du programme, il faut les enregistrer.

On pourrait enregistrer chaque attribut dans un fichier séquentiel (FileOpen puis Print..).

On peut aussi utiliser la sérialisation.

La Sérialisation:

La sérialisation est le processus de conversion d'un objet ou d'un groupe d'objets en séquence linéaire d'octets pour stockage ou transmission à un autre emplacement. La désérialisation est le processus consistant à accepter des informations stockées et à recréer des objets à partir de celles-ci.

La sérialisation consiste donc à stocker les valeurs des attributs d'une instance d'un objet dans un fichier qui peut être au format binaire, xml ou Soap.

La sérialisation binaire concerne les champs publics et privés de l'objet et le nom de la classe, y compris l'assembly contenant la classe.

La sérialisation XML ne sérialise que les champs publics et les valeurs des propriétés d'un objet (si elles ne sont pas en lecture seule) dans un flux XML. La sérialisation n'inclut pas d'informations de type.

Lors de la sérialisation, les champs et propriétés sont convertis en un flux d'octets, qui est alors écrit dans un flux de données enregistré sur le disque ou envoyé sur internet.

Lorsque l'objet est ensuite désérialisé,le flux de données venant d'un fichier donne un flux d'octets qui donne une valeur aux champs et propriétés de l'objet, on obtient un objet identique à l'objet d'origine. 

Vous pouvez aussi sérialiser un objet et le transporter sur Internet entre un client et un serveur à l'aide du protocole HTTP. À l'autre extrémité, la désérialisation reconstruit l'objet à partir du flux.

 
Exemple 1: Sérialisation binaire.
Créons une mini Classe:

<Serializable()> Public Class Compta

Public Total As Double

Public Taux As Double

End Class

Notons que pour que la classe soit sérialisable , il faut ajouter <Serializable()>.

L'attribut Serializable indique donc au compilateur que tout ce que contient la classe peut être conservé dans un fichier.

L'attribut NonSerialized peut être utilisé pour marquer les membres de la classe qui ne doivent pas être conservés.

Pour empêcher la sérialisation d'un membre Customer par exemple:

 <NonSerialized()> Public Customer As String

 
Sérialisation:
Dans le corps du programme, il faut mettre:

Imports System.IO

Imports System.Runtime.Serialization.Formatters.binary

Dans ce cas, vous utilisez un flux de sortie et un formateur binaire pour enregistrer l'objet dans un format binaire.

Dans l'entête du module créons une objet MyCompta:

Private myCompta As New Compta

Donnons des valeurs a ses membres.

myCompta.Taux = 2

myCompta.Total = 100

Si on quitte le programme, les valeurs sont perdues!!! On va donc les enregistrer dans un fichier "compta.bin"

Dim myFileStream As Stream = File.Create("Compta.bin")

Dim serializer As New BinaryFormatter

serializer.Serialize(myFileStream, myCompta)

myFileStream.Close()

Et voilà un fichier compta.bin a été crée sur le disque, il contient:

"Bin=  ÿÿÿÿ Kserialisation, Version=1.0.1994.38183, Culture=neutral, PublicKeyToken=null serialisation.MaClasse Total Taux Y@ @ "

On a bien enregistré les valeurs des variables d'une instance dans un fichier.

Déserialisation:

Lors de la prochaine utilisation du logiciel,on crée de nouveau une instance de Compta:

Private myCompta As New Compta

Il faut ensuite 'récupérer' les valeurs de l'instance:

Dans  Form1_Load par exemple:

Private Sub Form1_Load()
    If File.Exists("Compta.bin") Then
        Dim myFileStream As Stream = File.OpenRead("Compta.bin")
        Dim deserializer As New BinaryFormatter()
        myCompta = CType(deserializer.Deserialize(myFileStream), Compta)
        myFileStream.Close()
    End If
End Sub

A noter que vous devez d'abord vérifier que le fichier existe. S'il existe, créez une classe Stream pour lire le fichier binaire et une classe BinaryFormatter pour convertir le fichier. La méthode CType est utilisée pour la conversion du type d'objet Stream en type Compta.

Ca marche, on retrouve bien MyCompta.Taux=2

Bien sur , si on sérialise une nouvelle fois, cela écrase le précédent fichier.

 

Exemple 2: Sérialisation Xml.

Pour les applications Web ou les services Web XML, vous souhaiterez peut-être conserver l'objet dans un fichier XML à l'aide d'un format SOAP, ce qui facilite le partage de l'objet.

il faut charger dans les références la dll .Net System.Runtime.Serialization.Formatters.Soap.dll
Ensuite Imports System.Runtime.Serialization.Formatters.Soap
Dim deserializer As New SoapFormatter
Remplacez  "SavedCompta.bin" par "SavedCompta.xml".

Cela donne:

Imports System.IO

Imports System.Runtime.Serialization.Formatters.Soap

Private MyCompta As New MaClasse

 

Sérialisation:

MyCompta.Taux = 3

MyCompta.Total = 100

Dim myFileStream As Stream = File.Create("SaveCompta.xml")

Dim serializer As New SoapFormatter

serializer.Serialize(myFileStream, MyCompta)

myFileStream.Close()

Déserialisation:

Dim myFileStream As Stream = File.OpenRead("saveCompta.bin")

Dim deserializer As New soapFormatter

MyCompta = CType(deserializer.Deserialize(myFileStream), MaClasse)

MsgBox(MyCompta.Taux.ToString)

myFileStream.Close()

 

Si on regarde le fichier SavedCompta.xml (il est dans le répertoire bin) on voit que c'est de l'Xml:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:MaClasse id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/serialisation/serialisation%2C%20Version%3D1.0.1995.

30938%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
<Total>100</Total>
<Taux>3</Taux>
</a1:MaClasse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

On se rend compte que la sérialisation binaire produit un fichier plus petit.

 

Exemple 3: Sérialisation d'une collection:

On peut sérialiser un objet, on peut donc sérialiser toutes sortes objets (dit serialisable) , une image, une collection, un tableau....

Une collection est un objet, pour enregistrer son contenu, on peut donc le sérialiser.

Imports System.IO
Imports System.Collections
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization


Module MonModule

    
' Creation d'une hashtable contenant des noms et adresses.
        Public addresses As New Hashtable
        addresses.Add("Phil", "12 grand rue,69872")
        addresses.Add("Bob", "98 petite rue, 196")
        addresses.Add("Marie", "BP 89, Paris, 75200")

    Sub Serialisation()

        
        ' Pour serialiser la hashtable (et les clé/valeur),  
        Dim fs As New FileStream("MesAdresses.dat", FileMode.Create)
        Dim formatter As New BinaryFormatter
        Try
            formatter.Serialize(fs, addresses)
        Catch e As SerializationException
            Console.WriteLine("Echec serialisation. Cause: " & e.Message)
            Throw
        Finally
            fs.Close()
        End Try
    End Sub



    Sub Deserialisation()
        ' Declaration de la HashTable.
        Dim addresses As Hashtable = Nothing
        Dim fs As New FileStream("DataFile.dat", FileMode.Open)
        Try
            Dim formatter As New BinaryFormatter

            addresses = DirectCast(formatter.Deserialize(fs), Hashtable)
        Catch e As SerializationException
            Console.WriteLine("Echec de deserialisation. Cause: " & e.Message)
            Throw
        Finally
            fs.Close()
        End Try

    End Sub
End Module
 

Exemple 4: Sérialisation d'un tableau:

 

Private MyCompta(10) As String

MyCompta(1) = "3"

MyCompta(2) = "100"

Sérialisation:

Dim myFileStream As Stream = File.Create("SaveCompta.xml")

Dim serializer As New SoapFormatter

serializer.Serialize(myFileStream, MyCompta)

myFileStream.Close()

Déserialisation:

Dim myFileStream As Stream = File.OpenRead("saveCompta.xml")

Dim deserializer As New soapFormatter

MyCompta = DirectCast(deserializer.Deserialize(myFileStream), String())

MsgBox(MyCompta(1).ToString)

myFileStream.Close()

Vous avez compris. Seule difficulté: le caste en String().

Bien sur, cela marche avec un tableau à plusieurs dimensions. Voyons les lignes à modifier

Private MyCompta(10,10) As String

MyCompta(1,1) = "3"

Dans la déserialisation:

MyCompta = DirectCast(deserializer.Deserialize(myFileStream), String(,))

 

Exemple 5: Sérialisation d'une collection généric

Ici nous enregistrons les données dans un fichier XML nommé "Meslivres.Xml" (il sera dans le répertoire bin/Debug lors de la conception, et dans le répertoire de l'exécutable si on installe le logiciel).

 

Les Sub SaveData et LoadData ont en paramètre un type de collection généric list( Of  ClasseLivre) C'est une collection d'objets typés  ClasseLivre .Ce paramètre est passé avec ByRef .

(Pour l'exemple complet voir le chapitre architecture)

 

Imports System.Xml.Serialization

Imports System.IO

 

Public Class AccesAuxDonnees

 

Public Sub SaveData(ByVal list As Collections.Generic.List(Of ClasseLivre))

' Déclaration

Dim serialXML As Xml.Serialization.XmlSerializer = Nothing

Dim streamIO As StreamWriter = Nothing

Try

serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))

' Ouverture d'un flux en écriture sur le fichier XML des contacts

streamIO = New StreamWriter("Meslivres.Xml")

' Sérialisation de la liste des contacts

serialXML.Serialize(streamIO, list)

Catch ex As Exception

' Propagrer l'exception

Throw ex

Finally

' En cas d'erreur, n'oublier pas de fermer le flux en écriture si ce dernier est toujours ouvert

If streamIO IsNot Nothing Then

streamIO.Close()

End If

End Try

End Sub

 

Public Sub LoadData(ByRef list As Collections.Generic.List(Of ClasseLivre))

' Déclaration

Dim streamIO As StreamReader = Nothing

Dim serialXML As Xml.Serialization.XmlSerializer = Nothing

Try

' Tester l'existance du fichier

If System.IO.File.Exists("Meslivres.Xml") = True Then

serialXML = New Xml.Serialization.XmlSerializer(GetType(Collections.Generic.List(Of ClasseLivre)))

' Ouverture d'un flux en lecture sur le fichier XML des contacts

streamIO = New StreamReader("Meslivres.Xml")

' Désérialisation de la liste des contacts

list = CType(serialXML.Deserialize(streamIO), Collections.Generic.List(Of ClasseLivre))

End If

Catch ex As Exception

' Propagrer l'exception

Throw ex

Finally

' En cas d'erreur, n'oublier pas de fermer le flux en lecture si ce dernier est toujours ouvert

If streamIO IsNot Nothing Then

streamIO.Close()

End If

End Try

End Sub

End Class

Voila ce que donne le fichier XMl:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClasseLivre xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ClasseLivre>
<Titre>Livre1</Titre>
<Auteur>Auteur1</Auteur>
</ClasseLivre>
<ClasseLivre>
<Titre>Livre2</Titre>
<Auteur>Auteur2</Auteur>
</ClasseLivre>
<ClasseLivre>
<Titre>Titre3</Titre>
<Auteur>Auteur3</Auteur>
</ClasseLivre>
</ArrayOfClasseLivre>