C # Сериализация контрактов данных из файла - PullRequest
4 голосов
/ 14 октября 2011

У меня есть список сообщений 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 ]

2 голосов
/ 15 октября 2011

Когда вы десериализуете данные из файла, 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);
    }
}
0 голосов
/ 14 октября 2011
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)); 
}
0 голосов
/ 14 октября 2011

Возможно, ваш файл содержит BOM Это обычно для кодировки UTF-8

...