使用MemoryStream将数据写入XML

8
我注意到写入数据到 XML 文件有两种不同的方法(为了简洁起见,省略了错误处理)。
第一种方法是先构建 XML 文档,然后直接将 XML 保存到文件中:
using (XmlWriter writer = XmlWriter.Create(fileName))
{
    writer.WriteStartDocument(true);
    writer.WriteStartElement("parentelement");
    writer.WriteEndElement();
    writer.WriteEndDocument();
}

第二种方法是创建一个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方法是否会提供原子写入事件和/或在添加条目到XML文件时保护免受写入问题?

有人能解释一下这是否真的必要,还是只是在我的项目中添加不必要的代码行?

6个回答

15

MemoryStream版本在这种情况下是浪费的。如果您想执行Stream类似的工作,但不需要实际文件,那么MemoryStream非常有用。如果您正在编写文件,则只需将其写入文件即可。这样可以避免需要在内存中缓冲所有数据。


3

虽然内存流方法对于简单操作来说可能是浪费的,但它非常适用于将XML保存为加密文件、压缩文件等情况。


2

这太过于复杂且浪费。

两种关键方法基于:

  1. 在结束之前,您不知道文档的完整结构。
  2. 当您“创建”文档的部分时,您知道它们是该文档部分的最终形式。

第一种方法需要创建文档的内存模型(DOM就是为此设计的)。完成后,直接向文件流写入即可。

第二种方法允许您节省大量内存和复杂性,并简单地使用XmlWriter,它可以直接指向终端流(在本例中是文件流)。

在任何阶段都不需要使用MemoryStream。


1
我认为,如果在Web应用程序或Web服务中创建文档,则使用内存流会很有用。文件位置可能会与正在运行相同处理的另一个进程发生冲突,这可能导致无效结果。在内存流中,处理应该是分离的。

1
如果您希望确保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 很大时才更有意义)


想知道为什么这个答案还没有得到好的评分。据我所知,它以易于使用的方式回答了问题,并提供了所需的好处(确保“可以构建XML文件”,提供某种原子性)。 - Stéphane Gourichon
哇,除了这个之外好像不行。原子移动和覆盖是Unix的专有名词吗?请参考https://dev59.com/LGPVa4cB1Zd3GeqP2RVs#10305475获取解决方法。 - Stéphane Gourichon

0
你不必使用MemoryStream来使用XmlWriter。XmlWriter可以直接写入文件;你可以使用另一个重载的XmlWriter.Create方法,它以文件名作为参数,或者你可以将其写入XmlTextWriter或FileStream,而不是写入MemoryStream。
因此,你的第二个代码片段可以这样写:
using( FileStream fs = ... )
{
    XmlWriter writer = XmlWriter.Create (fs);
}

据我所知,XmlWriter 不能保护您免于创建非规范的 Xml。

感谢您的回答... 我问题中提到的两种方法都能正常工作,毫无疑问... 我只是想尝试一下是否应该使用MemoryStream并获得一些澄清。 - Dscoduc
XmlWriter会保护您并强制执行格式良好的xml,除非:1)如果您使用WriteDocType或WriteRaw 2)如果您提前停止-即不要在结尾关闭所有元素到根元素 - ShuggyCoUk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接