【问题标题】:C# Serializing datacontracts from fileC#从文件中序列化数据契约
【发布时间】:2011-10-13 21:18:13
【问题描述】:

我有一个 Xml 消息列表,特别是我记录到文件中的 DataContract 消息。我正在尝试从文件中一一反序列化它们。我不想一次将整个文件读入内存,因为我希望它非常大。

我有这个序列化的实现,并且有效。我通过使用 FileStream 序列化并读取字节并使用正则表达式来确定元素的结尾来做到这一点。然后获取元素并使用 DataContractSerializer 获取实际对象。

但有人告诉我我应该使用更高级别的代码来完成这项任务,而且这似乎应该是可能的。我有以下代码,我认为它应该可以工作,但它没有。

FileStream readStream = File.OpenRead(filename);
DataContractSerializer ds = new DataContractSerializer(typeof(MessageType));
MessageType msg;
while ((msg = (MessageType)ds.ReadObject(readStream)) != null)
{
    Console.WriteLine("Test " + msg.Property1);
}

上面的代码输入了一个包含以下内容的输入文件:

<MessageType>....</MessageType>
<MessageType>....</MessageType>
<MessageType>....</MessageType>

看来我可以正确读取和反序列化第一个元素,但之后它就失败了:

System.Runtime.Serialization.SerializationException was unhandled
  Message=There was an error deserializing the object of type MessageType. The data at the root level is invalid. Line 1, position 1.
  Source=System.Runtime.Serialization

我在某处读到这是由于 DataContractSerializer 使用填充的“\0”到最后的方式 - 但我无法弄清楚如何在从流中读取而不弄清楚结尾时解决这个问题MessageType 标记的其他方式。我应该使用另一个序列化类吗?或者也许是解决这个问题的方法?

谢谢!

【问题讨论】:

    标签: c# filestream datacontractserializer


    【解决方案1】:

    当您从文件中反序列化数据时,WCF 默认使用只能使用正确 XML 文档的阅读器。您正在阅读的文档不是 - 它包含多个根元素,因此它实际上是一个片段。您可以通过使用ReadObject 的另一个重载(如下例所示)将序列化程序正在使用的阅读器更改为接受片段的阅读器(通过使用XmlReaderSettings 对象)。或者,您可以在 &lt;MessageType&gt; 元素周围放置某种包装元素,并且您会一直阅读,直到读者位于包装器的末尾元素为止。

    public class StackOverflow_7760551
    {
        [DataContract]
        public class Person
        {
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
    
            public override string ToString()
            {
                return string.Format("Person[Name={0},Age={1}]", this.Name, this.Age);
            }
        }
    
        public static void Test()
        {
            const string fileName = "test.xml";
            using (FileStream fs = File.Create(fileName))
            {
                Person[] people = new Person[]
                { 
                    new Person { Name = "John", Age = 33 },
                    new Person { Name = "Jane", Age = 28 },
                    new Person { Name = "Jack", Age = 23 }
                };
    
                foreach (Person p in people)
                {
                    XmlWriterSettings ws = new XmlWriterSettings
                    {
                        Indent = true,
                        IndentChars = "  ",
                        OmitXmlDeclaration = true,
                        Encoding = new UTF8Encoding(false),
                        CloseOutput = false,
                    };
                    using (XmlWriter w = XmlWriter.Create(fs, ws))
                    {
                        DataContractSerializer dcs = new DataContractSerializer(typeof(Person));
                        dcs.WriteObject(w, p);
                    }
                }
            }
    
            Console.WriteLine(File.ReadAllText(fileName));
    
            using (FileStream fs = File.OpenRead(fileName))
            {
                XmlReaderSettings rs = new XmlReaderSettings
                {
                    ConformanceLevel = ConformanceLevel.Fragment,
                };
                XmlReader r = XmlReader.Create(fs, rs);
                while (!r.EOF)
                {
                    Person p = new DataContractSerializer(typeof(Person)).ReadObject(r) as Person;
                    Console.WriteLine(p);
                }
            }
    
            File.Delete(fileName);
        }
    }
    

    【讨论】:

    • 应该在循环之外创建可重用的东西(XmlWriterSettings、DataContractSerializer),但很好的答案
    【解决方案2】:

    也许您的文件包含BOM UTF-8 编码很常见

    【讨论】:

      【解决方案3】:
      XmlSerializer xml = new XmlSerializer(typeof(MessageType));
      XmlDocument xdoc = new XmlDocument();
      xdoc.Load(stream);
      foreach(XmlElement elm in xdoc.GetElementsByTagName("MessageType"))
      {
          MessageType mt = (MessageType)xml.Deserialize(new StringReader(elm.OuterXml)); 
      }
      

      【讨论】:

      • 不会 xdoc.Load(stream) 将整个文件加载到内存中吗?如果是这样,我不想那样做。我的文件可以运行到 10-20 Gbs ..
      • 我不确定。如果是这样,你可以试试 XmlReader
      猜你喜欢
      • 1970-01-01
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多