2009-11-07 6 views
1

Je possède un tableau sérialisé d'un certain type. Existe-t-il un moyen d'ajouter de nouveaux objets à ce tableau sérialisé (sous une forme sérialisée) sans avoir besoin de lire la collection déjà enregistrée dans la mémoire?Ajout à une collection sérialisée

Exemple:

Je rencontre dans un file.xml, tableau XML sérialisée de l'entité contenant 10^12 éléments. Je dois ajouter 10^5 autres éléments au fichier sérialisé, mais je ne veux pas lire tous les précédents, ajouter les nouveaux et écrire un nouveau tableau dans un flux parce que cela nécessiterait beaucoup de ressources (en particulier de la mémoire) .

Si cela nécessite un sérialiseur binaire, cela ne me poserait aucun problème.

+1

Cette question est un méli-mélo. Qu'est-ce qu'un "tableau XML-sérialisé"? Juste un fichier XML avec un élément racine, puis beaucoup d'éléments enfants et aucune autre hiérarchie? La question dépend entièrement de la structure des données, et il existe très peu de détails à ce sujet. – mquander

+0

un tableau d'une classe sérialisée avec IFormatter.Serialize(). En fait, le type de sérialiseur n'a pas vraiment d'importance. J'utiliserais probablement le binaire plus tard pour des raisons de performance. –

Répondre

7

En général, la solution consiste à changer les octets XML, de cette façon vous n'aurez pas à tout lire comme en désérialisation.

Les étapes sont en général:

  1. Liste élément
  2. Ouvrez le flux de fichiers
  3. Stocker le noeud de fermeture du tableau
  4. SERIALIZE le nouvel élément
  5. Ecrire octets sérialisés à flux
  6. Écrivez le nœud de fermeture

code par exemple qui ajoutent un entier à un tableau sérialisé:

// Serialize array - in you case it the stream you read from file.xml 
var ints = new[] { 1, 2, 3 }; 
var arraySerializer = new XmlSerializer(typeof(int[])); 
var memoryStream = new MemoryStream(); // File.OpenWrite("file.xml") 
arraySerializer.Serialize(new StreamWriter(memoryStream), ints); 

// Save the closing node 
int sizeOfClosingNode = 13; // In this case: "</ArrayOfInt>".Length 
          // Change the size to fit your array 
          // e.g. ("</ArrayOfOtherType>".Length) 

// Set the location just before the closing tag 
memoryStream.Position = memoryStream.Length - sizeOfClosingNode; 

// Store the closing tag bytes 
var buffer = new byte[sizeOfClosingNode]; 
memoryStream.Read(buffer, 0, sizeOfClosingNode); 

// Set back to location just before the closing tag. 
// In this location the new item will be written. 
memoryStream.Position = memoryStream.Length - sizeOfClosingNode; 

// Add to serialized array an item 
var itemBuilder = new StringBuilder(); 
// Write the serialized item as string to itemBuilder 
new XmlSerializer(typeof(int)).Serialize(new StringWriter(itemBuilder), 4); 
// Get the serialized item XML element (strip the XML document declaration) 
XElement newXmlItem = XElement.Parse(itemBuilder.ToString()); 
// Convert the XML to bytes can be written to the file 
byte[] bytes = Encoding.Default.GetBytes(newXmlItem.ToString()); 
// Write new item to file. 
memoryStream.Write(bytes, 0, bytes.Length); 
// Write the closing tag. 
memoryStream.Write(buffer, 0, sizeOfClosingNode); 

// Example that it works 
memoryStream.Position = 0; 
var modifiedArray = (int[]) arraySerializer.Deserialize(memoryStream); 
CollectionAssert.AreEqual(new[] { 1, 2, 3, 4 }, modifiedArray); 
+0

Salut Elisha, cela semble être une réponse très intéressante, et j'ai voté. Pour les gens comme moi qui n'ont pas beaucoup d'expérience dans ce domaine, il serait utile que vous ajoutiez quelques autres commentaires dans votre code: par exemple, d'où vient la valeur # 13 utilisée (c'est basé sur votre connaissance de exactement combien d'octets écrit le tableau {1,2,3} de int dans un flux de mémoire prend?). Une autre question: votre exemple montre une modification d'un flux de mémoire (vous avez le fichier écrit en tant que XML commenté): cela peut-il être substitué à l'utilisation de flux de mémoire sans mods majeurs? merci, – BillW

+0

@BillW, ajouté quelques commentaires, ce n'est pas le code intuitif, donc j'espère que cela aide :) Le numéro # 13 va changer en fonction du type sérialisé. Il représente la longueur du nom de noeud qui ferme le tableau XML. Par exemple, prendra 16 octets (octet par caractère). J'ai utilisé MemoryStream juste pour rendre la réponse lisible et claire (je suppose que je n'ai pas eu trop de succès), mais elle partage la même base avec FileStream. Les deux sont stream, en remplaçant le premier bloc dans la vie réelle à File.OpenWrite ("fichier.xml") n'affectera pas le reste du code responsable de l'ajout du nouvel élément. – Elisha

Questions connexes