【问题标题】:Write XML directly to disk and append elements将 XML 直接写入磁盘并附加元素
【发布时间】:2012-04-20 20:16:41
【问题描述】:

我正在尝试编写一个 XML 文件,但它太大而无法存储在内存中,因此我想将其直接写入磁盘。我曾尝试使用 XmlWriter,但没有使我能够追加到文件末尾的功能,因此我愿意求助于使用常规文件编写器编写 XML 原始文件。

有谁知道任何文件写入类可以让我直接写入磁盘并且可以覆盖文件中的位置?

原因是我需要能够覆盖根元素的关闭,以便我可以附加另一位信息,而且还能够在需要时读取 XML 文件。例如,如果我有以下 XML:

<elements>
  <element>
  </element>
</elements>

如果我想读这个,我可以,但如果我想写,我必须先删除&lt;/elements&gt; 标签,添加另一个元素,然后再次添加结束标签。

感谢您的帮助。

【问题讨论】:

  • 很遗憾,XML 的设计方式使得无法追加。
  • 文件有多大,你的内存限制是多少?
  • 我的内存限制是 .NET 运行时的 1.5GB 限制,而且文件非常大。我还没有弄清楚它会有多大,但预计会有很多 GB。
  • 我认为您可以打开文件的流,搜索到最后,构建一个 XmlWriter 并将流传递给 Create...这不起作用吗?
  • 我不得不说,xml 似乎不是存储这些数据的最佳方式。是否可以更改架构以使标签名称更短(从而减小其大小)?它需要是 xml 文件而不是数据库中的原因吗?

标签: c# xml c#-4.0 file-io xmlwriter


【解决方案1】:

可以使用 XmlTextWriter。

只需打开文件进行写入,返回到结束元素的开头,然后使用 XmlTextWriter 附加任何您想要的新元素。要关闭文件,只需为 end 元素编写原始文本以使文档完整,然后就完成了。

这是一个快速而肮脏的例子。

像这样从 XML 开始:

<?xml version="1.0" encoding="utf-8"?>
<DocumentElement>
    <FirstElem/>
</DocumentElement>

你可以打开它并像这样附加一个元素:

using (FileStream f = new FileStream(@"D:\a.xml", FileMode.OpenOrCreate, FileAccess.Write))
{
    f.Seek(-("</DocumentElement>\n".Length), SeekOrigin.End);
    using (XmlTextWriter x = new XmlTextWriter(f, Encoding.UTF8))
    {
        x.WriteStartElement("Another");
        x.WriteAttributeString("attr", "value");
        x.WriteEndElement();

        // Close the file with a new terminating end-element
        x.WriteRaw("\r\n</DocumentElement>\r\n");
    }
}

结果是:

<?xml version="1.0" encoding="utf-8"?>
<DocumentElement>
    <FirstElem/>
<Another attr="value" />
</DocumentElement>

您可能无法获得完美的缩进等,但它是有效的 XML。如果将 xml 作为原始文本写入文件,这正是您要做的 - 但您也可以利用 XML 编写器为您进行格式化。

我也同意一些 cmets - 为您的 xml 使用最小化大小的模式将非常有益。关闭缩进。尽可能使用最短的元素和属性名称。如果您正在处理叶元素,将数据存储为属性而不是 cdata 将节省空间(&lt;element&gt;data&lt;/element&gt;&lt;element val="data"/&gt; 更昂贵,并且可以进一步压缩到 &lt;e v="data"/&gt; - 几乎是原始大小的一半)

【讨论】:

  • 我可以验证这是否有效,尽管使用 Environment.NewLine 比使用 \r\n 更好。那是我唯一的修改。谢谢!
  • 我确实说过这是一个快速而肮脏的例子! :-)
【解决方案2】:

我假设(正如@payo 的评论所建议的那样)您可以使用文件流、XmlTextReader(将流定位到适当的元素)和XmlWriter 的组合来写入新元素,然后重写结束元素。

【讨论】:

  • 他在问题中明确表示XmlWriter 对他不起作用。
  • ...然后连接流(+1 克里斯,我打算建议这个)
  • @Thomas 你是对的,我的错。我已经对其进行了更新,以说明在使用 XmlReader 和 XmlWriter 之后如何完成 OP。
  • @ChrisShain 关于 XmlReader 的好点(找到正确的注入点)。我掩盖了这一点。我曾经为一个太大而无法实际加载到内存中的数据流编写了一个反序列化器 - 使用 XmlReader 和智能流搜索(并非所有数据都需要反序列化)。
猜你喜欢
  • 2011-02-20
  • 2017-10-19
  • 2012-01-15
  • 1970-01-01
  • 2014-11-23
  • 2017-10-02
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
相关资源
最近更新 更多