在C#中将数据保存到文件

10

我目前正致力于开发一款用于Pathfinder角色扮演游戏的自动化角色表项目,并遇到了保存数据的问题。我希望将所有变量的当前值保存到一个后缀为.pfcsheet的文件中,并在以后打开它。我搜索了谷歌,但没有找到关于如何做到这一点的信息,只有如何保存文本框的内容。我尝试使用saveFileDialog控件,但它一直提示“文件名无效”错误,而且似乎没有人知道原因。


你可以将对象序列化为XML字符串,然后将该字符串写入文件,并自定义文件名和扩展名。 - Ayush
1
@xbonez 我有一种感觉,如果他们在使用文件保存对话框时遇到困难,那么序列化就不可能了。也许需要一些教程。 - Michael Todd
@MichaelTodd:作为答案,我添加了更多细节。序列化可能有点棘手。 - Ayush
谢谢大家的帮助,我会研究序列化。 - Excelzn
为了以后参考,请在开始实际项目时,始终指定文件格式是否由某个接口控制文档固定。请考虑格式的前向和后向兼容性。并且,在求助于在线论坛之前,请尽力自己进行研究... - Deer Hunter
7个回答

29
我刚刚写了一篇关于将对象数据保存为二进制、XML或Json格式的博客文章(链接)。听起来你可能想使用二进制序列化,但也许你希望文件在应用程序外部进行编辑,在这种情况下,XML或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();
    }
}

例子

// To save the characterSheet variable contents to a file.
WriteToBinaryFile<CharacterSheet>("C:\CharacterSheet.pfcsheet", characterSheet);

// To load the file contents back into a variable.
CharacterSheet characterSheet = ReadFromBinaryFile<CharacterSheet>("C:\CharacterSheet.pfcsheet");

你有点晚了,不是吗?被你回答的问题是在2012年提出的。 - Robert Harvey
33
@RobertHarvey 当然,这是针对楼主的建议,但其他人(比如我自己)仍然会通过搜索引擎一直找到这篇帖子,因此有更多答案和例子可以学习总是很好的。 - deadlydog
@deadlydog 感谢您提供的优秀代码示例。我想知道为什么在Write函数中包含了bool append,如果在Read函数中没有办法读取多个序列化实例的话。换句话说,由于无论如何都不能从同一个文件中读取多个写入,那么append不总是为false吗? - ZX9
@ZX9 是的,你说得对,如果你计划稍后只是用它来读取序列化,那么你可能不需要 append 布尔值。我只是在万一用户想要将许多不同的实例转储到一个 xml 文件中以便稍后人工阅读时,才包含它。 - deadlydog
非常出色,轻松地为我节省了几个小时 - 谢谢。 - Ory Zaidenvorm

15

我认为你可能需要像这样的东西

// Compose a string that consists of three lines.
string lines = "First line.\r\nSecond line.\r\nThird line.";

// Write the string to a file.
System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt");
file.WriteLine(lines);

file.Close();

3

请查看 XMLSerializer 类。

如果您想保存对象的状态并能够在另一个时刻轻松地重新创建它们,则序列化是最好的选择。

将其序列化以便返回完整的 XML。使用 StreamWriter 类将此写入文件。

稍后,您可以读取文件的内容,并将其传递给序列化器类,同时还需要提供一个要填充的对象实例,序列化器也会处理反序列化。

这里是从 Microsoft Support 中摘取的代码片段:

using System;

public class clsPerson
{
  public  string FirstName;
  public  string MI;
  public  string LastName;
}

class class1
{ 
   static void Main(string[] args)
   {
      clsPerson p=new clsPerson();
      p.FirstName = "Jeff";
      p.MI = "A";
      p.LastName = "Price";
      System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());

      // at this step, instead of passing Console.Out, you can pass in a 
      // Streamwriter to write the contents to a file of your choosing.
      x.Serialize(Console.Out, p);


      Console.WriteLine();
      Console.ReadLine();
   }
} 

此外,除了序列化允许您将对象的当前状态作为可持久化数据输出之外,XML序列化还会生成一个可以称为“人类可读”的文件,并且很容易解析为另一个程序的输入。 - KeithS

3

这是一个类似于Sachin的简单示例。建议在未管理的文件资源上使用“using”语句:

        // using System.IO;
        string filepath = @"C:\test.txt";
        using (StreamWriter writer = new StreamWriter(filepath))
        {
            writer.WriteLine("some text");
        }

using 语句 (C# 参考)


3

2

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接