.net中的流式XML序列化

我正在尝试使用XmlSerializer序列化一个非常大的IEnumerable ,而不会将所有对象保留在内存中。

IEnumerable实际上是懒惰的..

我正在寻找一种流媒体解决方案:

  1. 使用标准序列化从IEnumerable序列化到底层流中的对象( 我不想在这里手工处理XML!
  2. 丢弃内存数据并移至下一个

我正在尝试使用此代码:

 using (var writer = new StreamWriter(filePath)) { var xmlSerializer = new XmlSerializer(typeof(MyObject)); foreach (var myObject in myObjectsIEnumerable) { xmlSerializer.Serialize(writer, myObject); } } 

但我得到多个XML标头,我无法指定根标签所以我的XML无效。

任何的想法?

谢谢

XmlWriter类是用于生成XML的快速流API。 它是相当低级的,MSDN有一篇关于使用XmlWriter.Create()实例化validationXmlWriter的文章 。

编辑:链接已修复。 以下是文章中的示例代码:

 async Task TestWriter(Stream stream) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Async = true; using (XmlWriter writer = XmlWriter.Create(stream, settings)) { await writer.WriteStartElementAsync("pf", "root", "http://ns"); await writer.WriteStartElementAsync(null, "sub", null); await writer.WriteAttributeStringAsync(null, "att", null, "val"); await writer.WriteStringAsync("text"); await writer.WriteEndElementAsync(); await writer.WriteCommentAsync("cValue"); await writer.WriteCDataAsync("cdata value"); await writer.WriteEndElementAsync(); await writer.FlushAsync(); } } 

这是我使用的:

 using System; using System.Collections.Generic; using System.Xml; using System.Xml.Serialization; using System.Text; using System.IO; namespace Utils { public class XMLSerializer { public static Byte[] StringToUTF8ByteArray(String xmlString) { return new UTF8Encoding().GetBytes(xmlString); } public static String SerializeToXML(T objectToSerialize) { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings {Encoding = Encoding.UTF8, Indent = true}; using (XmlWriter xmlWriter = XmlWriter.Create(sb, settings)) { if (xmlWriter != null) { new XmlSerializer(typeof(T)).Serialize(xmlWriter, objectToSerialize); } } return sb.ToString(); } public static void DeserializeFromXML(string xmlString, out T deserializedObject) where T : class { XmlSerializer xs = new XmlSerializer(typeof (T)); using (MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(xmlString))) { deserializedObject = xs.Deserialize(memoryStream) as T; } } } } 

然后打电话:

 string xml = Utils.SerializeToXML(myObjectsIEnumerable); 

我没有试过它,例如, IEnumerable一次一个地获取一个对象,或任何其他奇怪的用例,但它适用于List和内存中的其他集合。

编辑 :根据您对此的评论,您可以使用XmlDocument.LoadXml将生成的XML字符串加载到XmlDocument ,将第一个XML字符串保存到文件中,并将其用作主XML文件。 对于IEnumerable中的每个项目,再次使用LoadXml创建一个新的内存中XmlDocument ,获取所需的节点,将它们附加到主文档,然后再次保存,删除新的。

完成后,可能有一种方法可以包装根标记中的所有节点。 您还可以使用XSL和XslCompiledTransform编写另一个XML文件,其中包含正确包装在根标记中的对象。

您可以通过在大类上实现IXmlSerializable接口来完成此操作。 WriteXml方法的实现可以编写开始标记,然后简单地遍历IEnumerable并将每个MyObject序列化为同一个XmlWriter ,一次一个。

在此实现中,将不会任何内存中的数据(废弃收集器将收集的内容)。