Сериализация и десериализация в файл XML, C # - PullRequest
1 голос
/ 04 июня 2009

У меня есть следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication28
{
class Program
{

    static void Main()
    {
        List<string> dirs = FileHelper.GetFilesRecursive(@"c:\Documents and Settings\bob.smith\Desktop\Test");
        foreach (string p in dirs)
        {
            Console.WriteLine(p);
        }

        //Write Count
        Console.WriteLine("Count: {0}", dirs.Count);
        Console.Read();

    }

    static class FileHelper
    {
        public static List<string> GetFilesRecursive(string b)
        {
            // 1.
            // Store results in the file results list.
            List<string> result = new List<string>();

            // 2.
            // Store a stack of our directories.
            Stack<string> stack = new Stack<string>();

            // 3.
            // Add initial directory.
            stack.Push(b);

            // 4.
            // Continue while there are directories to process
            while (stack.Count > 0)
            {
                // A.
                // Get top directory
                string dir = stack.Pop();

                try
                {
                    // B
                    // Add all files at this directory to the result List.
                    result.AddRange(Directory.GetFiles(dir, "*.*"));

                    // C
                    // Add all directories at this directory.
                    foreach (string dn in Directory.GetDirectories(dir))
                    {
                        stack.Push(dn);
                    }
                }
                catch
                {
                    // D
                    // Could not open the directory
                }
            }
            return result;
        }
    }
}
}

Приведенный выше код хорошо работает для рекурсивного поиска файлов / каталогов, находящихся в папке на моем c:.
Я пытаюсь сериализовать результаты того, что этот код делает с файлом XML, но я не уверен, как это сделать.

Мой проект такой: найти все файлы / каталоги на диске, сериализовать в файл XML. Затем, во второй раз, когда я запускаю это приложение, у меня будет два XML-файла для сравнения. Затем я хочу десериализовать файл XML с первого запуска этого приложения, сравнить различия с текущим файлом XML и создать отчет об изменениях (то есть, файлы, которые были добавлены, удалены, обновлены).

Я надеялся получить некоторую помощь, так как я новичок в C #, и я очень и очень шокирован сериализацией и десериализацией. У меня много проблем с кодированием. Кто-нибудь может мне помочь?

Спасибо

Ответы [ 7 ]

3 голосов
/ 04 июня 2009

Ваш результат - List<string>, и его нельзя сериализовать напрямую. Вам придется обернуть его, минимальный подход:

[Serializable]
class Filelist: List<string> {  }

И затем (Де) Сериализация идет как:

Filelist data = new Filelist(); // replaces List<string>

// fill it

using (var stream = File.Create(@".\data.xml"))
{
    var formatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
    formatter.Serialize(stream, data);
}    

data = null; // lose it

using (var stream = File.OpenRead(@".\data.xml"))
{
    var formatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
    data = (Filelist) formatter.Deserialize(stream);
}

Но учтите, что вы не будете сравнивать XML никоим образом (не практично). Вы будете сравнивать (десериализовать) экземпляры List. И XML отформатирован в SOAP, взгляните на это. Это может быть не очень полезно в другом контексте.

И, следовательно, вы можете легко использовать другой форматер (двоичный файл немного более эффективен и гибок).

Или, может быть, вы просто хотите сохранить Список файлов в формате XML. Это другой вопрос.

3 голосов
/ 17 августа 2009

Для тех, кто испытывает проблемы с сериализацией и десериализацией xml. Я создал образец класса, чтобы сделать это ниже. Он работает и для рекурсивных коллекций (например, файлов и каталогов).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sample
{
        [Serializable()]
        [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "rootnode")]
        public partial class RootNode
        {

            [System.Xml.Serialization.XmlElementAttribute("collection1")]
            public List<OuterCollection> OuterCollections { get; set; }
        }

        [Serializable()]
        public partial class OuterCollection
        {

            [XmlAttribute("attribute1")]
            public string attribute1 { get; set; }

            [XmlArray(ElementName = "innercollection1")]
            [XmlArrayItem("text", Type = typeof(InnerCollection1))]
            public List<InnerCollection1> innerCollection1Stuff { get; set; }

            [XmlArray("innercollection2")]
            [XmlArrayItem("text", typeof(InnerCollection2))]
            public List<InnerCollection2> innerConnection2Stuff { get; set; }
        }

        [Serializable()]
        public partial class InnerCollection2
        {

            [XmlText()]
            public string text { get; set; }
        }

        public partial class InnerCollection1
        {

            [XmlText()]
            public int number { get; set; }
        }
}
1 голос
/ 05 июня 2009

Джон:

Могу ли я предложить улучшение? Вместо использования имен файлов используйте объект FileInfo . Это позволит вам получить гораздо более точную информацию о каждом файле, а не только, если он существует под тем же именем.

Кроме того, класс XmlSerializer должен нормально работать. Он не будет сериализовывать общие списки, поэтому вам придется вывести свой List <> в массив или что-то подобное, но кроме этого:

 XmlSerializer serial = new XmlSerializer(typeof(FileInfo[]));
 StringWriter writer = new StringWriter(); 
 FileInfo[] fileInfoArray = GetFileInfos(); 
 serial.Serialize(writer, fileInfoArrays);

Просто и легко, если вам не важно, как выглядит сериализованный XML.

Что бы вы ни делали, потеряйте пустой блок улова. Вы будете сожалеть о глотании исключений. Войдите их или перебросьте их.

1 голос
/ 04 июня 2009

Этот класс сериализует и десериализует себя .... надеюсь, это поможет.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;

namespace TestStuff
{
    public class Configuration
    {
        #region properties

        public List<string> UIComponents { get; set; }
        public List<string> Settings { get; set; }

        #endregion

        //serialize itself
        public string Serialize()
        {
            MemoryStream memoryStream = new MemoryStream();

            XmlSerializer xs = new XmlSerializer(typeof(Configuration));
            using (StreamWriter xmlTextWriter = new StreamWriter(memoryStream))
            {
                xs.Serialize(xmlTextWriter, this);
                xmlTextWriter.Flush();
                //xmlTextWriter.Close();
                memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                memoryStream.Seek(0, SeekOrigin.Begin);
                StreamReader reader = new StreamReader(memoryStream);

                return reader.ReadToEnd();
            }
        }

        //deserialize into itself
        public void Deserialize(string xmlString)
        {
            String XmlizedString = null;

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (StreamWriter w = new StreamWriter(memoryStream))
                {
                    w.Write(xmlString);
                    w.Flush();

                    XmlSerializer xs = new XmlSerializer(typeof(Configuration));
                    memoryStream.Seek(0, SeekOrigin.Begin);
                    XmlReader reader = XmlReader.Create(memoryStream);

                    Configuration currentConfig = (Configuration)xs.Deserialize(reader);

                    this.Settings = currentConfig.Settings;
                    this.UIComponents = currentConfig.UIComponents;

                    w.Close();
                }
            }
        }
        static void Main(string[] args)
        {
            Configuration thisConfig = new Configuration();
            thisConfig.Settings = new List<string>(){
                "config1", "config2"
            };
            thisConfig.UIComponents = new List<string>(){
                "comp1", "comp2"
            };
            //serializing the object
            string serializedString = thisConfig.Serialize();


            Configuration myConfig = new Configuration();
            //deserialize into myConfig object
            myConfig.Deserialize(serializedString);
        }
    }


}
0 голосов
/ 09 июня 2009

Этот вопрос точно такой же, как этот. У меня также есть опубликованный ответ, который также будет работать для вас:

Как сериализовать?

0 голосов
/ 05 июня 2009

для сериализации XML, у вас есть несколько возможностей:

  • Делаем это вручную
  • Использование XmlSerializer, как описано выше
  • Использование System.Xml.Serialization
  • Использование Linq to Xml

для последних двух см. Пример кода в этом ответе. (См. Некоторые ошибки здесь )

А для вашего рекурсивного посетителя каталога вы можете сделать его действительно рекурсивным: вот несколько интересных примеров кода.

0 голосов
/ 04 июня 2009

Помощь № 1. Сделайте отступ кода на четыре пробела, чтобы при размещении здесь его можно было увидеть как код.

2: избавьтесь от этого блока try / catch, так как он сожрет все исключения, включая те, о которых вы хотите знать.

3: Вы вообще пытались сериализовать свои результаты? Пожалуйста, измените свой вопрос, чтобы показать, что вы пытались. Подсказка: используйте класс XmlSerializer.

...