【问题标题】:Serialization and Deserialization into an XML file, C#序列化和反序列化为 XML 文件,C#
【发布时间】:2009-06-04 18:23:28
【问题描述】:

我有以下代码:

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# 的初学者,我在序列化和反序列化方面非常不稳定。我在编码时遇到了很多麻烦。有人可以帮我吗?

谢谢

【问题讨论】:

    标签: c# serialization xml-serialization


    【解决方案1】:

    您的结果是List&lt;string&gt;,它不能直接序列化。您必须将其包装起来,这是一种最小的方法:

    [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。那是一个不同的问题。

    【讨论】:

      【解决方案2】:

      适用于在 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:您说您创建这些类是“为了做到这一点”,但我没有看到他们任何事情。
      • 正如他所说,这是一个“样本”类。它有所有常用的元素,你不需要做任何事情,但你必须声明它。非常感谢
      【解决方案3】:

      这个类对自身进行序列化和反序列化......希望这会有所帮助。

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

      【讨论】:

      • @CSharpAll:如果抛出异常,您的类也会泄漏资源:不使用块。
      • 我是否遗漏了任何 Using 语句?我正在使用这些:使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Text;使用 System.Xml;使用 System.Runtime.Serialization;使用 System.Xml.Serialization;使用 System.IO;
      • 如果您使用的是我的确切类....SerializableDictionary 是我的对象(不在示例中)。
      • 这是我的错误:找不到类型或命名空间名称“RegisteredUIComponent”(您是否缺少 using 指令或程序集引用?)并且同样的错误...除了“serializabledictionary”我该如何解决这个问题?
      • 这两个类都是我的类...它们不是框架的一部分。我只是给你一个序列化和反序列化的例子......把你自己的属性放在那里。
      【解决方案4】:

      约翰:

      我可以提出改进建议吗?不要使用文件名,而是使用FileInfo object。这将允许您获得有关每个文件的更准确的信息,而不仅仅是它是否以相同的名称存在。

      此外,XmlSerializer 类应该可以满足您的需求。它不会序列化通用列表,因此您必须将 List 输出到数组或类似的数组中,但除此之外:

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

      简单易行,除非序列化 XML 的外观对您很重要。

      无论你做什么,都会丢失空的 catch 块。你会后悔吞下异常。记录它们或重新扔掉它们。

      【讨论】:

        【解决方案5】:

        帮助 #1。将代码缩进四个空格,以便在此处发布时将其视为代码。

        2:去掉那个 try/catch 块,因为它会吃掉所有异常,包括你想知道的那些。

        3:您是否尝试过对结果进行序列化?请编辑您的问题以显示您的尝试。提示:使用 XmlSerializer 类。

        【讨论】:

        • 好吧,我不清楚如何准确地实现 XMLSerializer 类。我已经做 C# 3 个月了......而且我的知识差距很大。我确实遵循了我在网上找到的示例,但我不知道如何使用该示例来帮助我......以及将任何代码本身放在哪里。
        • @yeahumok:您可能需要考虑“寻找示例”是否是您学习的正确方式。有些人以这种非结构化的方式学习得很好。其他人则要求已经知道知识结构的人以合理的顺序呈现它。也许这就是你需要的。也许像msdn.microsoft.com/en-us/library/90c86ass(VS.85).aspx 这样的东西会帮助你,而不是你碰巧找到的随机例子。
        【解决方案6】:

        对于 xml 序列化,你有几种可能:

        • 手动操作
        • 如上所述使用 XmlSerializer
        • 使用 System.Xml.Serialization
        • 使用 Linq to Xml

        对于最后两个,请参阅this 答案中的代码示例。 (查看一些陷阱here

        对于递归目录访问者,您可以考虑使其真正递归:here's 一些有趣的代码示例。

        【讨论】:

          【解决方案7】:

          这个问题和这个问题一模一样。我也发布了一个对您也有用的答案:

          How to serialize?

          【讨论】:

            猜你喜欢
            • 2012-02-02
            • 2013-10-08
            • 2011-05-12
            • 1970-01-01
            • 2011-06-28
            • 1970-01-01
            • 2010-11-25
            • 1970-01-01
            相关资源
            最近更新 更多