【问题标题】:How to quickly save/load class instance to file如何快速保存/加载类实例到文件
【发布时间】:2011-05-15 02:11:10
【问题描述】:

我的应用中有几个类/结构的集合。

类只是一个有字段的类

class A
{
  public int somevalue;
  public string someothervalue
}

还有我的收藏

List<A> _myList;

我需要能够保存 _myList 并加载。我只想将所有类字段保存到文件并加载。我不想花时间编写自己的保存/加载。 .NET 中是否有任何工具可以帮助我。我不在乎文件格式。

【问题讨论】:

  • 这个集合有多大?您打算将这些类中的多少放入集合中?您对此评论的回复将取决于我发布的答案。
  • 不少,不到一百。这只是一个测试项目,应用程序在启动时加载集合并在退出时保存。我只是不想花时间在这上面。因为我不断地添加新的类和集合。
  • 您要保存字段或属性吗?一些序列化器(BinarySerializer)在字段上工作,其他(XmlSerializer)在公共属性上工作。
  • 好问题。我只对公共领域很好。

标签: c# .net file serialization


【解决方案1】:

我刚刚写了a blog post on saving an object's data to Binary, XML, or Json;很好地将对象或对象列表写入文件。以下是各种格式的功能。有关详细信息,请参阅我的博文。

二进制

/// <summary>
/// Writes the given object instance to a binary file.
/// <para>Object type (and all child types) must be decorated with the [Serializable] attribute.</para>
/// <para>To prevent a variable from being serialized, decorate it with the [NonSerialized] attribute; cannot be applied to properties.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the XML file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the XML file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToBinaryFile<T>(string filePath, T objectToWrite, bool append = false)
{
    using (Stream stream = File.Open(filePath, append ? FileMode.Append : FileMode.Create))
    {
        var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        binaryFormatter.Serialize(stream, objectToWrite);
    }
}

/// <summary>
/// Reads an object instance from a binary file.
/// </summary>
/// <typeparam name="T">The type of object to read from the XML.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the binary file.</returns>
public static T ReadFromBinaryFile<T>(string filePath)
{
    using (Stream stream = File.Open(filePath, FileMode.Open))
    {
        var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        return (T)binaryFormatter.Deserialize(stream);
    }
}

XML

需要将 System.Xml 程序集包含在您的项目中。

/// <summary>
/// Writes the given object instance to an XML file.
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute.</para>
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToXmlFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
    TextWriter writer = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        writer = new StreamWriter(filePath, append);
        serializer.Serialize(writer, objectToWrite);
    }
    finally
    {
        if (writer != null)
            writer.Close();
    }
}

/// <summary>
/// Reads an object instance from an XML file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the XML file.</returns>
public static T ReadFromXmlFile<T>(string filePath) where T : new()
{
    TextReader reader = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        reader = new StreamReader(filePath);
        return (T)serializer.Deserialize(reader);
    }
    finally
    {
        if (reader != null)
            reader.Close();
    }
}

Json

您必须包含对 Newtonsoft.Json 程序集的引用,该程序集可从 Json.NET NuGet Package 获得。

/// <summary>
/// Writes the given object instance to a Json file.
/// <para>Object type must have a parameterless constructor.</para>
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [JsonIgnore] attribute.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToJsonFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
    TextWriter writer = null;
    try
    {
        var contentsToWriteToFile = JsonConvert.SerializeObject(objectToWrite);
        writer = new StreamWriter(filePath, append);
        writer.Write(contentsToWriteToFile);
    }
    finally
    {
        if (writer != null)
            writer.Close();
    }
}

/// <summary>
/// Reads an object instance from an Json file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the Json file.</returns>
public static T ReadFromJsonFile<T>(string filePath) where T : new()
{
    TextReader reader = null;
    try
    {
        reader = new StreamReader(filePath);
        var fileContents = reader.ReadToEnd();
        return JsonConvert.DeserializeObject<T>(fileContents);
    }
    finally
    {
        if (reader != null)
            reader.Close();
    }
}

示例

// Write the list of objects to a file.
WriteToXmlFile<List<A>>("C:\myObjects.txt", _myList);

// Read the list of objects from the file back into a variable.
List<A> _myList = ReadFromXmlFile<List<A>>("C:\myObjects.txt");

【讨论】:

    【解决方案2】:

    XMLSerializer 不难使用。只要您的对象不是很大,它就很快。我在我的一些应用程序中序列化了一些巨大的对象。这需要很长时间,生成的文件几乎是 100 兆,但如果我需要调整一些东西,它们是可编辑的。另外,我是否向对象添加字段也没关系。旧版本对象的序列化文件仍然可以正确反序列化。我在单独的线程上进行序列化,所以在我的情况下需要多长时间并不重要。需要注意的是,您的 A 类必须有一个构造函数才能使 XMLSerialziation 工作。

    这是我用来序列化/反序列化的一些工作代码,其中删除了错误处理以提高可读性...

    private List<A> Load()
    {
        string file = "filepath";
        List<A> listofa = new List<A>();
        XmlSerializer formatter = new XmlSerializer(A.GetType());
        FileStream aFile = new FileStream(file, FileMode.Open);
        byte[] buffer = new byte[aFile.Length];
        aFile.Read(buffer, 0, (int)aFile.Length);
        MemoryStream stream = new MemoryStream(buffer);
        return (List<A>)formatter.Deserialize(stream);
    }
    
    
    private void Save(List<A> listofa)
    {
        string path = "filepath";
        FileStream outFile = File.Create(path);
        XmlSerializer formatter = new XmlSerializer(A.GetType());
        formatter.Serialize(outFile, listofa);
    }
    

    【讨论】:

    • 演示中的coilsfile 是什么?
    • 看起来这是一个错字。试图删除任何特定于代码的东西,原来的FileStream 可能被称为coilsfile。在我的清理工作中,我忽略了将 coilsfile 重命名为 aFile。但现在已经三年了,很难说。不过,很好的收获。哇。编辑以反映这一点。
    • 请,请,请在打开 FileStream 和 MemoryStream 时使用“using”以避免内存泄漏。
    【解决方案3】:

    有很多序列化器:

    .net 框架的一部分

    • XmlSerializer(标准化格式,缓慢而冗长)
    • BinarySerializer(专有格式,中等速度,支持循环图,序列化字段而不是属性 => 烦人的版本控制

    第三方:

    • Json-Serializers(标准化格式,基于文本,比 xml 更短)
    • ProtoBuf-Serializers(标准化格式,二进制,非常快)

    如果文件可能是二进制文件,我可能会使用 ProtoBuf 序列化程序,如果需要纯文本,我可能会使用 json 序列化程序。

    【讨论】:

    • DataContractJsonSerializer 是 3.5 及更高版本 (System.Runtime.Serialization.Json) 的一部分。尽管对于这个特定的实例,BinaryFormatter 将是一个不错的选择。
    • 我不使用标准的 BinaryFormatter,因为它的文件格式不透明,而且它使用私有字段会破坏封装并导致版本控制问题。
    【解决方案4】:

    老话题,但我修改了上面 Tim Coker 的答案,以利用 using 块正确处理流对象并一次只保存一个类实例:

    public static T Load<T>(string FileSpec) {
        XmlSerializer formatter = new XmlSerializer(typeof(T));
    
        using (FileStream aFile = new FileStream(FileSpec, FileMode.Open)) {
            byte[] buffer = new byte[aFile.Length];
            aFile.Read(buffer, 0, (int)aFile.Length);
    
            using (MemoryStream stream = new MemoryStream(buffer)) {
                return (T)formatter.Deserialize(stream);
            }
        }
    }
    
    public static void Save<T>(T ToSerialize, string FileSpec) {
        Directory.CreateDirectory(FileSpec.Substring(0, FileSpec.LastIndexOf('\\')));
        FileStream outFile = File.Create(FileSpec);
        XmlSerializer formatter = new XmlSerializer(typeof(T));
    
        formatter.Serialize(outFile, ToSerialize);
    }
    

    【讨论】:

    • outFile使用后需要dispose,或者使用using。您在 Load 但未在 Save 中正确处理了 Streams。
    【解决方案5】:

    您可以使用 XML 序列化器或二进制序列化器序列化您的 List&lt;&gt;,并将序列化列表保存到文件中。

    稍后,您可以阅读此文件内容并检索您的原始列表。

    创建您要为其创建列表的类型[Serializable]

    【讨论】:

    • 谢谢。那么字典呢?相同?或者我自己的 IEnumerable/IEnumerator 集合
    【解决方案6】:

    我通常使用 XML Serilizer,它速度快、易于实现,并且可以以人类可读的方式保持对象,你可以看到一个不错的 example

    如果您想要更有效的模糊解决方案,您可以使用二进制序列化。 (例如,如果您想通过网络传输序列化。)

    编辑:要更好地控制您序列化的元素,请查看example

    【讨论】:

    • 很好的例子。但。容器包装在 Serializable 类中。如何序列化“只有一个 List 类型的变量”。
    • 您好,您需要使用XmlArray和XmlArrayItem控件属性,看看新的例子。您必须序列化列表的容器,并且列表必须是公共属性。
    【解决方案7】:

    我们可以通过以下方式之一从文件中保存和加载对象。

    二进制序列化、Xml序列化、Json序列化

    public enum Serialization
    {
        BinarySerialization = 1,
        XmlSerialization = 2,
        JsonSerialization = 3,
    }
    public static void SaveObjectToFile<T>(Serialization serialization, string filePath ,T objectToSave)
    {
        Directory.CreateDirectory(filePath.Substring(0, filePath.LastIndexOf('\\')));
         using (StreamWriter writer = new StreamWriter(filePath))
        {
            switch (serialization)
            {
                case Serialization.XmlSerialization: //Object type must have a parameterless constructor
                    XmlSerializer formatter = new XmlSerializer(typeof(T));
                    //Use the [XmlIgnore] attribute to exclude a public property or variable from being written to the file.(in XML Serialization only)
                    formatter.Serialize(writer, objectToSave);
                    break;
                case Serialization.JsonSerialization: //Object type must have a parameterless constructor
                    var contentsToWriteToFile = Newtonsoft.Json.JsonConvert.SerializeObject(objectToSave);
                    //[JsonIgnore] attribute to exclude a public property or variable from being written to the file.
                    writer.Write(contentsToWriteToFile);
                    break;
                case Serialization.BinarySerialization: 
                    var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    //decorate class (and all classes that it contains) with a [Serializable] attribute.Use the [NonSerialized] attribute to exclude a variable from being written to the file;
                    binaryFormatter.Serialize(writer.BaseStream, objectToSave);
                    break;
            }
        }
    }
    public static T LoadObjectToFile<T>(Serialization serialization, string filePath)
    {
        using (StreamReader reader = new StreamReader(filePath))
        {
            switch (serialization)
            {
                case Serialization.XmlSerialization:
                    XmlSerializer formatter = new XmlSerializer(typeof(T));
                    return (T)formatter.Deserialize(reader);
                case Serialization.JsonSerialization:
                    var fileContents = reader.ReadToEnd();
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(fileContents);
                case Serialization.BinarySerialization:
                    var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    return (T)binaryFormatter.Deserialize(reader.BaseStream);
                default:
                     throw new System.ArgumentOutOfRangeException("Serialization = "+Convert.ToString(serialization));
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多