C#从文件中序列化datacontracts

时间:2011-10-13 21:18:14

标签: c# filestream datacontractserializer

我有一个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标记。是否有我应该使用的另一个序列化类?或者解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:2)

当您从文件反序列化数据时,WCF默认使用只能使用正确XML文档的阅读器。您正在阅读的文档不是 - 它包含多个根元素,因此它实际上是片段。您可以通过使用另一个ReadObject重载来更改序列化程序正在使用的阅读器,如下例所示,接受片段(使用XmlReaderSettings对象)。或者你可以在<MessageType>元素周围放置一些包装元素,然后你会阅读,直到读者定位在包装器的结束元素上。

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

答案 1 :(得分:0)

也许您的文件包含BOM 它通常用于UTF-8编码

答案 2 :(得分:0)

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