C#从文件序列化数据合同 [英] C# Serializing datacontracts from file
问题描述
我有一个Xml消息列表,特别是我记录到文件中的DataContract消息.我正在尝试将它们从文件一个开始反序列化.我不想立即将整个文件读入内存,因为我希望它很大.
I have a list of Xml messages specifically DataContract messages that i record to a file. And i am trying to deserialize them from file one by one. I do not want to read the whole file into memory at once because i expect it to be very big.
我已经实现了该序列化,并且可以正常工作.我通过使用FileStream进行序列化并读取字节并使用正则表达式来确定元素的结尾来做到这一点.然后获取元素并使用DataContractSerializer获取实际对象.
I have an implementation of this serialization and that works. I did this by serializing using a FileStream and reading the bytes and using regular expression to determine the end of element. Then taking the element and using DataContractSerializer to get the actual object.
但是我被告知我应该使用更高级别的代码来完成此任务,而且似乎应该可行.我有以下代码,我认为应该可以,但不能.
But i was told I should be using higher level code to do this task and it seems like that should be possible. I have the following code that i think should work but it doesn't.
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);
}
上面的代码中包含了包含以下内容的输入文件:
The above code is fed with an input file containing something along the following lines:
<MessageType>....</MessageType>
<MessageType>....</MessageType>
<MessageType>....</MessageType>
看来我可以正确读取和反序列化第一个元素,但之后却无法显示:
It appears that i can read and deserialize the first element correctly but after that it fails saying:
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标记.我应该使用另一个序列化类吗?还是解决这个问题的方法?
I have read somewhere that it is due to the way DataContractSerializer works with padded '\0''s to the end - but i couldn't figure out how to fix this problem when reading from a stream without figuring out the end of MessageType tag in some other way. Is there another Serialization class that i should be using? or perhaps a way around this problem?
谢谢!
推荐答案
当您从文件中反序列化数据时,WCF默认使用读取器,该读取器只能使用适当的XML文档.您正在阅读的文档不是-它包含多个根元素,因此实际上是片段.您可以通过使用另一个重载ReadObject
(如下面的示例所示),将序列化程序使用的读取器更改为可以接受片段的重载程序(通过使用XmlReaderSettings
对象).或者,您可以在<MessageType>
元素周围使用某种包装元素,然后进行读取,直到将阅读器放在包装器的末尾元素上为止.
When you're deserializing the data from the file, WCF uses by default a reader which can only consume proper XML documents. The document which you're reading isn't - it contains multiple root elements, so it's effectively a fragment. You can change the reader the serializer is using by using another overload of ReadObject
, as shown in the example below, to one which accepts fragments (by using the XmlReaderSettings
object). Or you can have some sort of wrapping element around the <MessageType>
elements, and you'd read until the reader were positioned at the end element for the wrapper.
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);
}
}
这篇关于C#从文件序列化数据合同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!