2009-05-16 18 views
13

persone,Come scrivere (grande) XML in un file in C#?

Per favore, qual è un buon modo di scrivere documenti XML veramente grandi (fino a 500 MB) in C# .NET 3.5? Ho avuto un po 'di ricerca in giro, e non riesco a trovare nulla che indirizzi questa domanda specifica.

mio thread precedente (What is the best way to parse (big) XML in C# Code?) coperto di lettura simili documenti Xml grandezza ... Con che risolto ho bisogno di pensare a come scrivere le funzioni aggiornate (http://www.opengeospatial.org/standards/sfa) a un documento "update.xml".

Le mie idee: Ovviamente un grande DOM è fuori, considerando la dimensione massima del documento da produrre. Sto usando XSD.EXE per generare classi vincolanti dallo schema ... che funziona bene con la classe XmlSerializer, ma penso che costruisca un DOM "sotto il cofano". È corretto?. Non riesco a tenere tutte le funzionalità (fino a 50.000 di esse) in memoria contemporaneamente. Ho bisogno di leggere una feature dal database, serializzarla e scriverla su file. Quindi penso che dovrei usare XmlSerializer per scrivere un "doclet" per ogni singola caratteristica del file. Non ho idea (ancora) se questo è anche possibile/fattibile.

Cosa ne pensi?

Background: sto porting un vecchio VB6 MapInfo "plug-client" per C#. Esiste un "servizio di aggiornamento" J2EE esistente (in realtà solo un'app web) con il quale questo programma (tra gli altri) deve collaborare. Non riesco a cambiare il server; a meno che non sia necessario per necessità; in particolare, ciò comporta la modifica degli altri client. Il server accetta un documento XML con uno schema che non specifica nessuno spazio dei nomi ... cioè: c'è solo spazio dei nomi predefinito, e tutto è in esso.

La mia esperienza: Sono praticamente un novizio C# e .NET. Ho programmato per circa 10 anni in varie lingue, tra cui Java, VB, C e alcuni C++.

Saluti tutti. Keith.

PS: È ora di cena, quindi resterò AWOL per circa mezz'ora.

risposta

16

Per scrivere xml di grandi dimensioni, XmlWriter (direttamente) è tuo amico - ma è più difficile da utilizzare. L'altra opzione sarebbe quella di utilizzare approcci/oggetto-modello DOM e combinarli, che è probabilmente fattibile se si prendere il controllo del XmlWriterSettings e disattivare il marcatore XML e sbarazzarsi delle dichiarazioni di namespace ...

using System; 
using System.Collections.Generic; 
using System.Xml; 
using System.Xml.Serialization;  
public class Foo { 
    [XmlAttribute] 
    public int Id { get; set; } 
    public string Bar { get; set; } 
} 
static class Program { 
    [STAThread] 
    static void Main() { 
     using (XmlWriter xw = XmlWriter.Create("out.xml")) { 
      xw.WriteStartElement("xml"); 
      XmlSerializer ser = new XmlSerializer(typeof(Foo)); 
      XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
      ns.Add("",""); 
      foreach (Foo foo in FooGenerator()) { 
       ser.Serialize(xw, foo, ns); 
      } 
      xw.WriteEndElement(); 
     } 
    }  
    // streaming approach; only have the smallest amount of program 
    // data in memory at once - in this case, only a single `Foo` is 
    // ever in use at a time 
    static IEnumerable<Foo> FooGenerator() { 
     for (int i = 0; i < 40; i++) { 
      yield return new Foo { Id = i, Bar = "Foo " + i }; 
     } 
    } 
} 
+0

Marc, Merci. (Come per un mio commento alla risposta di David Schmitt) proverò in entrambe le direzioni e farò alcuni test delle prestazioni. Grazie signore per la risposta premurosa e il codice di esempio. Eccezionale. Ta. ;-) Spero solo di poter ripagare il favore un giorno. Cheers. Keith. – corlettk

-1

Perché non utilizzare semplicemente un TextWriter per scrivere l'XML?

+0

Perché XML non è testo. –

+5

"...non * semplicemente * testo. ";-) – Cerebrus

+0

Non vedere affatto il materiale Infoset XML (http://www.w3.org/TR/xml-infoset/) .Non confondere i dati con la loro rappresentazione. –

9

Utilizzare un XmlWriter:

[...] uno scrittore che fornisce un modo veloce, non memorizzato nella cache, significa forward-only di flussi di generazione o file contenenti dati XML.

+0

Spot on target! +1 – Cerebrus

+0

OK Proverò in entrambi i modi (solo per gli elementi chiave, per risparmiare tempo) in un prototipo. XmlWriter ha l'aspetto di " la risposta giusta ", ma suppongo che richiederà molto più codice rispetto alla mia soluzione XmlSerializer iniziale e inoltre annullerà e benefici di "flessibilità" dell'uso di classi di bind generate ... perché il codice di scrittura fatto a mano deve sapere tutto sullo schema esatto. Ti ringrazio per il tuo tempo ... Cheers. Keith. – corlettk

1

Hai pensato di comprimerlo prima di scriverlo su disco? Con XML puoi raggiungere più di 10 volte la compressione e ancora di più. probabilmente ci vorrà meno tempo per comprimere il file e scrivere la versione compressa piuttosto che leggere l'intera versione da 500Mb.

+1

Il problema più grande è che la rappresentazione DOM in memoria è in genere> x10 dell'effettivo xml sottostante ... e 5Gb è troppo grande per gestirlo in modo ragionevole. E ancora non aiuta se c'è un'API esistente/aspettativa di un file non compresso. –

+0

È una buona idea. Grazie. Posso anche comprimerlo prima che colpisca il disco; risparmiando tempo (e memoria) a leggerlo e inviarlo come HttpWebRequest. La nostra esperienza con questo XML si comprime a circa un quarto della sua dimensione esplosa ... saving (3/4) * 500 = 375 MB di RAM. – corlettk