2009-01-28 30 views
8

He notado dos enfoques diferentes para escribir datos en un archivo XML (manejo de errores omitido por brevedad).Uso de MemoryStream para escribir en XML

El primer método tiene que construir el documento XML y luego simplemente guardar el XML en un archivo:

using (XmlWriter writer = XmlWriter.Create(fileName)) 
{ 
    writer.WriteStartDocument(true); 
    writer.WriteStartElement("parentelement"); 
    writer.WriteEndElement(); 
    writer.WriteEndDocument(); 
} 

El segundo método tiene que crear un MemoryStream, y guarde el MemoryStream a un archivo:

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Indent = true; 
MemoryStream ms = new MemoryStream(); 
using (XmlWriter writer = XmlWriter.Create(ms, settings)) 
{ 
    writer.WriteStartDocument(true); 
    writer.WriteStartElement("parentelement"); 
    writer.WriteEndElement(); 
    writer.WriteEndDocument(); 
} 

using (FileStream fs = File.Open(fileName, FileMode.Create, FileAccess.Write)) 
{ 
    ms.WriteTo(fs); 
    ms.Dispose(); 
} 

Supongo que la lógica para usar un MemoryStream es asegurar que el archivo XML pueda construirse antes de intentar guardar el archivo. ¿El método MemoryStream proporcionará un evento de escritura atómica y/o protegerá contra problemas de escritura mientras agrega entradas al archivo XML?

¿Alguien puede explicar si esto es realmente necesario o simplemente una forma exagerada de agregar líneas innecesarias de código a mi proyecto?

Respuesta

15

La versión MemoryStream es un desperdicio en esta ocasión. MemoryStream es útil si desea realizar trabajos de Stream, pero no desea un archivo real. Si es escribiendo un archivo, solo escriba en el archivo. Esto evita la necesidad de almacenar todos los datos en la memoria.

0

No necesita usar un MemoryStream para usar el XmlWriter. El XmlWriter puede escribir directamente en un archivo; puede usar otra sobrecarga del método XmlWriter.Create, que toma un nombre de archivo como argumento, o en lugar de escribir en un MemoryStream, también puede escribir en un XmlTextWriter o un FileStream.

Por lo tanto, segundo codesnippet podría escribir como:

using(FileStream fs = ...) 
{ 
    XmlWriter writer = XmlWriter.Create (fs); 
} 

yo sepa, XmlWriter no le protegerá de la creación de un XML no bien formada.

+0

Gracias por la respuesta ... Ambos métodos en mi pregunta funcionan, sin lugar a dudas ... Solo quería intentar aclarar si debía usar MemoryStream o no. – Dscoduc

+0

XmlWriter lo protegerá y aplicará xml bien formado excepto: 1) si usa WriteDocType o WriteRaw 2) si se detiene antes, es decir, no cierre todos los elementos al elemento raíz al final – ShuggyCoUk

+0

Gracias por la aclaración ... – Dscoduc

2

Esto es excesivo y un desperdicio.

Los dos enfoques principales se basan en

  1. No se conoce la estructura completa del documento hasta el final.
  2. Cuando 'crea' las partes del documento, sabe que son la forma final de esta parte del documento.

la primera requiere la creación de un modelo en la memoria del documento (para el cual está diseñado el modelo DOM). Una vez que haya terminado, simplemente escribir directamente en la secuencia de archivos está bien.

El segundo permite ahorrar memoria y complejidad considerables y simplemente usa XmlWriter que puede apuntar directamente a la secuencia final (en este caso, una secuencia de archivos).

En ningún momento es necesario el uso de un MemoryStream

1

Si (por alguna razón) quiere garantizar los succeedes XmlWriter (es decir,de lo contrario el archivo podría ser truncado, pero en la mayoría de los casos esto será debido a - como se ha mencionado - etiquetas no cierre) se puede utilizar una secuencia de archivo temporal, fx algo similar a esto:

public class TempFileStream : FileStream 
{ 

    public TempFileStream(Action<string> onClose) 
     : base(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite) 
    { 
     this.CloseDelegate = onClose; 
    } 

    protected Action<string> CloseDelegate 
    { 
     get; 
     set; 
    } 

    public override void Close() 
    { 
     base.Close(); 
     if (File.Exists(this.Name)) 
     { 
      this.CloseDelegate(this.Name); 
     } 
    } 

} 

La utilizado como:

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Indent = true; 

using (TempFileStream tfs = new TempFileStream(f => File.Move(f, filename)) 
using (XmlWriter writer = XmlWriter.Create(tfs, settings)) 
{ 
    writer.WriteStartDocument(true); 
    writer.WriteStartElement("parentelement"); 
    writer.WriteEndElement(); 
    writer.WriteEndDocument(); 
} 

Esto no va a consumir una gran cantidad de memoria (por supuesto que sólo tiene/tiene más sentido cuando el XML resultante es grande)

+0

Te preguntas por qué esta respuesta aún no tiene una buena puntuación. AFAIK responde la pregunta con los beneficios solicitados (asegúrese de que "se pueda generar un archivo XML", proporcione algún tipo de atomicidad) de una manera fácil de usar. –

+0

Guau, excepto que no es así. ¿El movimiento atómico y sobrescribe un Unixismo? Vea http://stackoverflow.com/a/10305475/1429390 para una solución alternativa. –

3

es cierto que el enfoque secuencia de memoria es un desperdicio para operaciones simples, pero es muy útil para casos como guardar el xml como encriptación d archivo, como archivo comprimido, etc.

1

Creo que usar una secuencia de memoria sería útil si crea el documento en una aplicación web o servicio web. La ubicación del archivo puede entrar en conflicto con otro proceso que podría estar ejecutando el mismo proceso que podría causar resultados no válidos. En una secuencia de memoria, el procesamiento debe segregarse.

Cuestiones relacionadas