Sérialiser une arraylist

Résolu
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 - 22 juin 2005 à 17:09
scoubidou944 Messages postés 714 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 19 janvier 2017 - 8 févr. 2006 à 16:23
Bonjour,



alors, je viens de découvrir la sérialisation et juste après, j'ai découvert arraylist dont je ne méttais jamais servi.



Ce que je souhaite, c'est exporter en XML toutes les instances de ma
classe. Alors j'ai pensé mettre toutes ces instances dans un arraylist,
pour ensuite faire la sérialisation de toutes ces instances.

J'ai trouvé la méthode pour sérialiser un objet. Mais apparement, cela pose plus de problème pour un arraylist.



Le but de tout ça : je veux faire du stockage en dehors de mon appli,
je me suis orienté vers XML car je pense que cela correspond à mes
besoins, plus qu'une base de données.

Disons que j'ai une classe Fichier, dont chaque occurence possède 3 ou
4 propriétés d'un fichier. (numéro, statut, et nom du matériel)



Alors en fait, je télécharge d'un boîtier électronique une liste de fichiers avec leurs caractéristiques ci dessus. Je veux stocker cette liste à l'extérieur de l'application pour la retrouver au prochain lancement de cette dernière.

J'aurais donc par exemple dans l'ordre (n°, statut, nom):

instance1 : 1,statut1,machine1

instance2 : 2,statut2,machine2

instance3 : 3,statut2,machine1



Donc 3 instances de ma classe "fichier", que je voudrais pouvoir
retrouver lors de la prochaine exécution de l'appli. (et si possible,
les remettre dans des instances de fichier lors de la désérialisation)



J'arrive donc à la question : Quels est le format à adopter pour le
fichier XML (les balises, l'ordre, etc...car je ne sais pas du tout) et
comment envoyer dans un fichier XML toutes les instances de ma classe
fichier ? Est-ce que je peux passer par un arraylist ? Ou bien il faut
faire la sérialisation instance par instance ? (j'ai essayé cette
dernière solution, mais j'ai eu une erreur qui vient du format des
balises je pense)



Voilà ce que j'ai essayé :

private void ArrayListToXML_Click(object sender, System.EventArgs e)

{

XmlSerializer serialiseur = new XmlSerializer(typeof(Fichier));

TextWriter writer = new StreamWriter("monfichier.xml");

Fichier coucou;

foreach (object o in al)

{

coucou = (Fichier)o;

serialiseur.Serialize(writer,coucou);

}

writer.Close();

}



Alors, avec une seule instance dans l'arraylist, ca marche, voici le contenu du fichier XML :



<?xml
version="1.0" encoding="utf-8" ?>





[# -] <Fichier xmlns:xsd=" http://www.w3.org/2001/XMLSchema " xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance">






<numero>2</numero>





<date_debut>2005-06-22T17:02:52.3750000+02:00</date_debut>





<date_fin>2005-06-22T17:02:52.3750000+02:00</date_fin>





<duree>60</duree>





<statut>nouveau</statut>





<materiel>Epandeur 1</materiel>



</Fichier>




Mais, lorsque je crée une deuxième instance, voilà ce que j'obtient dans le contenu du fichier XML :

La page XML ne peut pas être affichée

Impossible d'afficher l'entrée XML en
utilisant la feuille de style XSL. Corrigez l'erreur, puis cliquez sur le bouton
[javascript:location.reload() Actualiser] ou réessayez
ultérieurement.


<hr>

Un seul élément de niveau supérieur est
autorisé dans un document XML. Erreur de traitement de la ressource
file:///D:/SATt...


<Fichier xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-^


Si vous en avoir une réponse, moi y'en a écouter vous avec plaisir.



Au passage, je pense que TheSaib a de l'info la dessus, j'ai vu un post à lui qui disait que arraylist n'est pas serialisable. Si tu peux me renseigner un peu plus

26 réponses

cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
22 juin 2005 à 17:43
Hello,
Puisque tu as une collection typée (composée uniquement de Fichier) alors tu peux créer une collection (dérivé de CollectionBase, ou utilisé les Generics si tu es sous VS2005). Supposons que cette collection s'appelle fc et est de type FichierCol, alors tu peux écrire pour sauver tout tes objects :


public void SaveFichier(string fileName, FichierCol fc)
{
XmlSerializer serializer = new XmlSerializer(typeof(FichierCol));
TextWriter writer = new StreamWriter(fileName);


try
{
serializer.Serialize(writer, fc);
}
catch
{
throw;
}
finally
{
writer.Close();
serializer = null;
}
}

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
23 juin 2005 à 17:20
Ouaip, bien vu SharpMao..


XmlSerializer xs = new XmlSerializer( typeof( ArrayList ), new Type[ ] { typeof( Fichier ) } );


TextWriter wr = new StreamWriter( "MyFile.xml" );


xs.Serialize( wr, list );


wr.Close();
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
22 juin 2005 à 18:30
Salut,

ArrayList a l'attribut [ Serializable ] donc ca devrait marcher, tu as essayé ? Je suis pas un spécialiste du XML mais ca me semble normal d'avoir l'erreur "Un seul élément de niveau supérieur est autorisé dans un document XML" si tu serializes instance par instance dans le même fichier.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
22 juin 2005 à 18:52
Tu peux essayer ca :

ArrayList list = new ArrayList( );

list.Add( 0 );
list.Add( 1 );

XmlSerializer xs = new XmlSerializer( typeof( ArrayList ) );
TextWriter wr = new StreamWriter( "MyFile.xml" );
xs.Serialize( wr, list );
wr.Close();
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
SharpMao Messages postés 1024 Date d'inscription mardi 4 février 2003 Statut Membre Dernière intervention 7 juin 2010 69
23 juin 2005 à 08:31
La raison pour laquelle ça ne marchait pas :

Comme te la dit le message d'erreur, XML n'accepte qu'une seule racine (Fichier dans ton exemple).
Si tu mets plusieurs <Fichier>, le XML n'est plus valide. Il faut donc une racine commune à ces <Fichier>.

Avec la solution de Lutinor, il va créer une racine , qui contiendra tes Fichiers.

Amicalement, SharpMao
0
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 9
23 juin 2005 à 14:11
Merci pour toutes vos réponses, j'ai pu tester ca ce matin. J'ai au passage apris comment on faisait une collection.



Voilà ce que j'arrive à écrire dans le fichier XML :


<?xml
version= "1.0" encoding="utf-8" ?>





[# -] <ArrayOfFichier xmlns:xsd=" http://www.w3.org/2001/XMLSchema " xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance">






[# -] <Fichier>






<numero>1</numero>





<date_debut>2005-06-23T12:29:41.6875000+02:00</date_debut>





<date_fin>2005-06-23T12:29:41.6875000+02:00</date_fin>





<duree>60</duree>





<statut>nouveau</statut>





<materiel>Epandeur 1</materiel>

</Fichier>








[# -] <Fichier>






<numero>2</numero>





<date_debut>2005-06-23T12:29:46.2187500+02:00</date_debut>





<date_fin>2005-06-23T12:29:46.2187500+02:00</date_fin>





<duree>50</duree>





<statut>téléchargé</statut>





<materiel>Epandeur 1</materiel>



</Fichier>










</ArrayOfFichier>



Je n'ai plus qu'à essayer de désérialiser tout cela, pour recréer les deux instances, et retrouver leur contenu.



>Lutinore : sur le lien suivant, TheSaib explique que arraylist n'est pas sérialisable, donc je n'ai pas essayé.



> Bidou : j'ai repris ton exemple avec
ma classe Fichier, j'ai crée une classe Fichiers qui dérive de
CollectionBase. Est-ce que tu peux m'expliquer à quoi try, catch, throw; finally servent ?



Je fais la désérialisation tantôt et je vous tiens au courant. Merci encore.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
23 juin 2005 à 14:36
Salut, j'avais regardé le lien suite à ton premier message.. Je ne sais pas pourquoi il dit ca.. faut peut etre s'entendre sur sérialiser un ArrayList et sérialiser son contenu !? J'ai pas testé la désérialisation mais le code de sérialisation que je t'ai donné il marche.. Mais la methode de Bidou est très bien de toute facon..

Euh, Bidou j'ai pas compris pourquoi tu relances l'exception dans ton catch !??
0
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 9
23 juin 2005 à 15:11
Je veux bien entendu exporter le contenu de tous mes objets, pour
pouvoir les retrouver lors d'un second lancement de l'application. Si
j'avais 13 instances, je veux recréer mes 13 instances, avec leurs
propriétés. Je pense que sérialiser / désérialiser permet de faire ça ?
0
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 9
23 juin 2005 à 16:15
J'ai donc essayé la désérialisation de ma collection, ca marche, c cool !



Par contre, j'ai voulu tester ta méthode Lutinore. Voilà ce que j'ai tapé :

private void ArrayListToXML_Click(object sender, System.EventArgs e)

{

XmlSerializer xs = new XmlSerializer(typeof(ArrayList));

TextWriter wr = new StreamWriter("MyFile.xml");

xs.Serialize(wr,al);

wr.Close();

}

al est mon objet arraylist déclaté dans ma form1 comme suit :

public ArrayList al = new ArrayList(10);



VS .NET 2003 plante à la ligne en vert (donc ca plante à xs.Serialize(wr,al);) et marque :

Une exception non gérée du type 'System.InvalidOperationException' s'est produite dans system.xml.dll



Informations supplémentaires : Erreur lors de la génération du document XML.



J'ai essayé avec :

al.add(0);

al.add(1);

Là ca marche, mais moi, j'ai essayé avec une arraylist al déjà remplie ailleurs mais par un fichier, pas par une valeur (al.add(mon_fichier));

Là ca plante.

Enfin, je n'ai pas pu rajouter [serializable] devant la déclaration de
mon arraylist al car c'est destiné aux classes, struc, et enum et pas
aux variables.
0
SharpMao Messages postés 1024 Date d'inscription mardi 4 février 2003 Statut Membre Dernière intervention 7 juin 2010 69
23 juin 2005 à 16:27
Pour que ça marche avec les ArrayList, le serializer doit connaître tous les types utilisés.

XmlSerializer xs = new XmlSerializer(typeof(ArrayList), new Type[]{mon_fichier.GetType()});

Amicalement, SharpMao
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
23 juin 2005 à 17:31
Ah non tu ne peux pas rajouter [ Serialisable ] à un objet.. Mais Arraylist a deja cet attribut c'est pour ca que dès le debut je t'ai dit que ca devrait marcher.. Mon exemple effectivement fonctionne mais comme il est simplifié, il correspondait pas à ton cas precis.. merci à SharpMao, j'avais pas encore compris l'utilité de ce constructeur..
0
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 9
Modifié le 26 mai 2018 à 17:35
Yes, d'ailleurs au passage, je préfère la version de Lutinore mon cher SharpMao. (je suis taquin)



En effet, mettre mon_fichier.gettype() suppose que tu
connaisses déjà le nom d'une occurence de la classe Fichier. Ce qui est
mon cas, mais par chance, car j'ai déclaré une variable de type Fichier
nommée Fichier_En_Cours dans ma class form1, pour une autre utilisation.

Le typeof(Fichier) me parait mieux car pas besoin de préciser une instance.



Merci pour tout les gars, ca marche nikel. (les deux méthodes : collection et arraylist)



Si qqln veut mon code, hésitez pas : <Supprimé sur demande>
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
23 juin 2005 à 17:41
Super, on s'améliore tous comme ca.. Mais sur ce coup je crois que c'est SharpMao qui mérite d'etre en VERT : )
0
SharpMao Messages postés 1024 Date d'inscription mardi 4 février 2003 Statut Membre Dernière intervention 7 juin 2010 69
23 juin 2005 à 17:46
Je suis d'accord avec toi el_teedee, la solution de Lutinore est plus élégante.

Je voulais juste montrer comment le faire avec des ArrayList.

Amicalement, SharpMao
0
scoubidou944 Messages postés 714 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 19 janvier 2017
23 juin 2005 à 18:10
et maintenant je pose la question piège, si la classe Fichier contient une Hashtable ?

(genre une hash de chak mot à laquelle correspond sa position dans le fichier).


Pour mon cas, j'utilise aussi XmlSerializer mais je n'ai trouvé ma vie sur le net qui s'intègre direct dans mon code.


----------------------------
C++ forever
C# amateur
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 juin 2005 à 08:18
Lutinore>
En fait, cette méthode est dans une classe de fonctionnalité (j'ai fait un c/c d'une partie de l'un de mes codes), class qu'on appelle sauf erreur aussi class Métier(?), et dans une telle classe je ne veux pas faire d'affichage graphique (pour annoncer une errreur). Le throw me permet de balancer l'exception plus loin quelque soit son type. Du coup, je la catch dans la partie graphique qui appelle cette méthode (ma winform qui possède un bouton sauver) et je fais un messageMox.

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 juin 2005 à 08:24
el_teedee>
Le bloc try-catch-finally me permet de gérer les erreurs. Quand on travaille avec les I/O, on a pleins de problèmes potentiels qui peuvent survenir. Si une erreur se produit lors de la sérialization de mon fichier, le bloc catch va s'exécuter (tu peux traiter ton erreur là). Dans mon cas, je fais un throw, je l'explique pourquoi juste en dessus à Lutinore.
Le bloc finally est un bloc toujours exécuté, erreur ou non. Praque pour faire du nettoyage de ressources, par exemple. En l'occurence je m'en sers pour fermer mes flux.


Sinon la meilleure solution c'est quand même de passer par des collections typées, c'est plus propre et ça facilite énormément la vie. Donc à mon avis tu peux laisser tomber l'ArrayList pour la Serialization ;-) Encore un petit détail, qui est plus une convention, Fichier est un mauvais nom pour une collection, appelle le plutôt FichierCollection ou à la limite Fichiers, mais pas Fichier.

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
0
el_teedee Messages postés 497 Date d'inscription mercredi 7 juillet 2004 Statut Membre Dernière intervention 13 juillet 2015 9
24 juin 2005 à 09:10
C'est ce que j'ai fait Bidou, ma classe d'éléments "fichier" est nommée
Fichier, (c'est une classe métier, si je ne m'abuse), et ma collection
est une classe nommée Fichiers.



C'est quand même énorme la méthode que tu as montré SharpMao, comme le
dit Lutinore. Si j'ai bien compris, tu lui passes d'une part le
type d'arraylist pour qu'il reconnaissance l'objet conteneur, puis tu
lui passes le type des instances, pour qu'il soit capable de
reconstituer les champs propriétés pour chaque instance. J'espère que
c'est une bonne explication, sinon on m'aurait menti ?



Sinon, j'ai deux autres questions d'ordre général :



1°) ma classe collection est dite typée car elle ne contient que des
objets de type Fichier. Mais à quel endroit on spécifie qu'elle est
typée ? C'est juste selon les constructeurs que l'on y met ? (elle est
typée car elle ne contient qu'un constructeur d'objet Fichier ?)



2°) Qu'elle est succintement la différence entre textwriter,
streamwriter et stringwriter ? J'ai vu qu'il existait les 3, et vu
aussi au passage dans les surchages des méthodes serialize et
deseriallize qu'elle pouvait prendre ces différentes variables:

un System.XML.XMLReader

un System.IO.TextReader

ou un System.IO.Stream (et aussi le system.IO.stringWriter)



Voili voilou...
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 juin 2005 à 09:26
scoubidou>
Je n'ai pas encore compris vraiment pourquoi, mais apparement une Hashtable ne peux pas être sérializée avec un XmlSerializer, cela vient du fait que le constructeur demande un Type, mais ne supporte pas le type Hashtable. Si tu fais un typeof(Hashtable) il retourne une exception disant que la Hashtable implémente IList (?).
La façon de contourner ce problème, c'est de passer par SOAP ou un BinaryFormatter. Je propose un petit exemple vite fait avec SOAP :


Ajouter une référence sur System.Runtime.Serialization.Formatters.Soap
faire un using System.Runtime.Serialization.Formatters.Soap;


Puis


public void SaveFichier(string fileName, Hashtable h)
{
SoapFormatter formatter = new SoapFormatter();


try
{
formatter.Serialize(new FileStream(fileName, FileMode.Create), h);
}
catch
{
...
}
finally
{
...
}
}

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
0
cs_Bidou Messages postés 5487 Date d'inscription dimanche 4 août 2002 Statut Membre Dernière intervention 20 juin 2013 61
24 juin 2005 à 09:36
1)
Avec le framework 2, le nouveau concepte des Generics permet de faire des collections qui sont réellement typées. Comme dans le framework 1.x on n'a pas encore cette notion, on la simule, si on veut bien, avec une CollectionBase qu'on dérive. Cette nouvelle collection contiendra typiquement une méthode Add, pour ton exemple public void Add(Fichier f) pour ajouter un type spécifique d'object => Collection typée. Du point de vue externe (utilisateur de la class), la collection est typée. D'un point de vue interne, on travail avec des objects qu'on cast chaque fois (en Fichier dans ton cas) pour que l'utilisateur est l'impression de travailler avec une collection typée.


2)
Je ne connais pas toutes les définitions des classes par coeur, le mieux c'est de regarder dans la documentation, dans MSDN y'a plus ou moins tout ce qu'il te faut. Mais en gros y'a pleins de possiblités pour lire/ecrire un fichier, et tout dépend la façon qu'on choisit, on a besoin d'un object adapté (textWriter, streamWriter, etc). Du coup, Serialize est surchargée pour pouvoir accepté tout ces types.

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
0
Rejoignez-nous