Использование MemoryStream для записи в XML

Я заметил два разных подхода к записи данных в файл XML (обработка ошибок для краткости опущена).

Первый способ заключается в создании XML-документа, а затем просто сохранении XML в файл:

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

Во втором методе вы создаете MemoryStream, а затем сохраняете MemoryStream в файл:

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();
}

Я предполагаю, что логика использования MemoryStream заключается в том, чтобы гарантировать, что файл XML может быть собран перед попыткой сохранить файл. Будет ли метод MemoryStream обеспечивать событие записи Atomic и / или защищать от проблем записи при добавлении записей в файл XML?

Может кто-нибудь объяснить, если это действительно необходимо, или просто излишний способ добавить ненужные строки кода в мой проект?

6 ответов

Решение

MemoryStream Версия по этому поводу расточительна. MemoryStream полезно, если вы хотите выполнить Stream как работа, но не хочу фактического файла. Если вы пишете файл, просто напишите в файл. Это позволяет избежать необходимости буферизовать все данные в памяти.

Это правда, что подход с использованием потока памяти является расточительным для простых операций, но он очень полезен для таких случаев, как сохранение XML-файла в виде зашифрованного файла, в виде сжатого файла и т. Д.

Это излишество и пустая трата времени.

Два ключевых подхода основаны на

  1. Вы не знаете всю структуру документа до конца.
  2. Когда вы "создаете" части документа, вы знаете, что они являются окончательной формой этой части документа.

первый требует создания модели документа в памяти (для которой предназначена модель DOM). Как только вы закончите с этим, просто пишите прямо в поток файлов.

Второй позволяет вам сэкономить значительную память и сложность и просто использовать XmlWriter, который может указывать непосредственно на конечный поток (в данном случае файловый поток).

Ни на каком этапе нет необходимости использовать MemoryStream

Если вы (по какой-то причине) хотите обеспечить успешное выполнение XmlWriter (т. Е. В противном случае файл может быть обрезан, но в большинстве случаев это будет связано с - как уже упоминалось - не с закрытием тегов), вы можете использовать временный файловый поток, например нечто похожее к этому:

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);
        }
    }

}

Используется как:

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();
}

Это не будет занимать много памяти (конечно, это имеет смысл только тогда, когда получающийся XML большой)

Я думаю, что использование потока памяти было бы полезно при создании документа в веб-приложении или веб-сервисе. Расположение файла может конфликтовать с другим процессом, который может выполнять ту же обработку, что может привести к неверным результатам. В потоке памяти обработка должна быть разделена.

Вам не нужно использовать MemoryStream для использования XmlWriter. XmlWriter может напрямую записывать в файл; вы можете использовать другую перегрузку метода XmlWriter.Create, который принимает имя файла в качестве аргумента, или вместо записи в MemoryStream вы также можете записать в XmlTextWriter или FileStream.

Итак, ваш второй кодекснипет может быть записан как:

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

AFAIK, XmlWriter не защитит вас от создания плохо сформированного Xml.

Другие вопросы по тегам