WinForm学习总结-(本地存储)

一、对象存储与序列化

1.1 对象存储的必要性

  • 对象存在于内存中,程序关闭后会被GC回收
  • 需要将对象状态持久化到磁盘,以便下次运行时恢复

1.2 简单文本存储方式

直接将对象属性写入文本文件,按行或分隔符区分:

public class People
{
    public string Name { get; set; }
    public string Age { get; set; }
    public string Sex { get; set; }
    public string Phone { get; set; }
}

// 写入对象
private void button1_Click(object sender, EventArgs e)
{
    People p = new People()
    {
        Name = textBox1.Text,
        Age = textBox2.Text,
        Sex = textBox3.Text,
        Phone = textBox4.Text
    };

    FileStream fs = new FileStream(@"1.txt", FileMode.Create);
    StreamWriter sw = new StreamWriter(fs);
    sw.WriteLine(p.Name);
    sw.WriteLine(p.Age);
    sw.WriteLine(p.Sex);
    sw.WriteLine(p.Phone);
    sw.Close();
    fs.Close();
}

// 读取对象
private void button2_Click(object sender, EventArgs e)
{
    People p1 = new People();

    using (FileStream fs = new FileStream(@"1.txt", FileMode.Open))
    {
        StreamReader sr = new StreamReader(fs);
        p1.Name = sr.ReadLine();
        p1.Age = sr.ReadLine();
        p1.Sex = sr.ReadLine();
        p1.Phone = sr.ReadLine();
    }

    textBox1.Text = p1.Name;
}

缺点:

  • 读取顺序必须与写入顺序一致,否则数据错乱
  • 属性较多时难以维护
  • 无法直接识别数据结构

1.3 序列化与反序列化概念

概念 说明
序列化 将对象状态转换为可保存或传输的格式(二进制、XML、JSON等)
反序列化 将序列化后的格式转换回对象

二、二进制序列化

2.1 实现步骤

  1. 在类上添加 [Serializable] 特性
  2. 使用 BinaryFormatter 进行序列化和反序列化

2.2 代码示例

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class Student
{
    public string Name { get; set; }
    public string Phone { get; set; }
}

public partial class Form1 : Form
{
    List<Student> list = new List<Student>();

    public Form1()
    {
        InitializeComponent();
        // 反序列化加载已有数据
        FileStream fs = new FileStream(@"1.txt", FileMode.Open);
        BinaryFormatter bf = new BinaryFormatter();
        List<Student> temp = bf.Deserialize(fs) as List<Student>;
        list.AddRange(temp);
        fs.Close();
    }

    // 序列化写入
    private void button1_Click(object sender, EventArgs e)
    {
        Student stu = new Student()
        {
            Name = "张三",
            Phone = "123456"
        };
        list.Add(stu);

        FileStream fs = new FileStream(@"1.txt", FileMode.Create);
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(fs, list);
        fs.Close();
    }

    // 反序列化读取
    private void button2_Click(object sender, EventArgs e)
    {
        FileStream fs = new FileStream(@"1.txt", FileMode.Open);
        BinaryFormatter bf = new BinaryFormatter();
        List<Student> ss = bf.Deserialize(fs) as List<Student>;
        
        string s = "";
        foreach (var item in ss)
        {
            s += item.Name + ":" + item.Phone;
        }
        this.Text = s;
        fs.Close();
    }
}

2.3 特点

  • 优点:存储效率高、速度快、支持复杂对象
  • 缺点:文件不可读、版本兼容性差、仅限.NET平台

三、JSON序列化

3.1 JSON格式简介

JSON(JavaScript Object Notation)是轻量级数据交换格式:

// 单个对象
{"Name":"张三","Age":18,"Sex":"男"}

// 对象数组
[{"Name":"张三","Age":18},{"Name":"李四","Age":20}]

语法规则:

  • [] 表示数组
  • {} 表示对象
  • 属性名必须加双引号
  • 属性值不能是函数
  • 最后一个属性后不能加逗号

3.2 原生方式 - DataContractJsonSerializer

需要引用 System.Runtime.Serialization 程序集:

using System.IO;
using System.Runtime.Serialization.Json;

public class People
{
    public string Name { get; set; }
    public string Age { get; set; }
    public string Sex { get; set; }
}

// 序列化写入
private void button1_Click(object sender, EventArgs e)
{
    People p1 = new People()
    {
        Name = textBox1.Text,
        Age = textBox2.Text,
        Sex = textBox3.Text,
    };

    FileStream fs = new FileStream(@"1.txt", FileMode.Create);
    DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(People));
    ds.WriteObject(fs, p1);
    fs.Close();
}

// 反序列化读取
private void button2_Click(object sender, EventArgs e)
{
    FileStream fs = new FileStream(@"1.txt", FileMode.Open);
    DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(People));
    People p1 = (People)ds.ReadObject(fs);
    fs.Close();
    this.Text = p1.Name;
}

3.3 第三方方式 - Newtonsoft.Json (Json.NET)

这是最常用的JSON处理库,功能强大且易用。

安装方式:

  • 右键项目 → 管理NuGet程序包 → 搜索 Newtonsoft.Json → 安装

代码示例:

using Newtonsoft.Json;
using System.IO;

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Info { get; set; }
}

public partial class Form1 : Form
{
    List<Student> list = new List<Student>();

    public Form1()
    {
        InitializeComponent();
        // 初始化测试数据
        for (int i = 0; i < 10; i++)
        {
            list.Add(new Student()
            {
                Name = "哈兰德" + i,
                Age = i * 10,
                Info = "前锋"
            });
        }
    }

    // 序列化
    private void button1_Click(object sender, EventArgs e)
    {
        string data = JsonConvert.SerializeObject(list);
        File.WriteAllText(@"1.txt", data);
    }

    // 反序列化
    private void button2_Click(object sender, EventArgs e)
    {
        string data = File.ReadAllText(@"1.txt");
        List<Student> students = JsonConvert.DeserializeObject<List<Student>>(data);
        
        string result = "";
        foreach (var item in students)
        {
            result += item.Name;
        }
        this.Text = result;
    }
}

3.4 复杂JSON解析

对于复杂JSON结构,需要根据JSON格式定义对应的类:

// 假设JSON格式:{"hits":{"topicMessageList":[{"author_name":"xxx","cover_image_url":"xxx"}]}}

public class XiaoShuoRoot
{
    public Hits hits { get; set; }
}

public class Hits
{
    public List<TopicMessageList> topicMessageList { get; set; }
}

public class TopicMessageList
{
    public string author_name { get; set; }
    public string cover_image_url { get; set; }
}

// 解析复杂JSON
private void button3_Click(object sender, EventArgs e)
{
    string data = File.ReadAllText(@"漫画.txt", Encoding.Default);
    XiaoShuoRoot root = JsonConvert.DeserializeObject<XiaoShuoRoot>(data);
    
    foreach (var item in root.hits.topicMessageList)
    {
        richTextBox1.Text += item.author_name + "\n";
    }
}

四、XML操作

4.1 XML格式简介

XML(eXtensible Markup Language)是可扩展标记语言:

<?xml version="1.0" encoding="utf-8" ?>
<Students>
    <Student>
        <StuName>高启强</StuName>
        <StuAge>48</StuAge>
        <StuGender></StuGender>
        <StuClass>C#一班</StuClass>
    </Student>
</Students>

格式要求:

  • 必须有唯一的根元素
  • 标签必须正确闭合
  • 元素必须正确嵌套
  • 属性值必须用引号括起来

4.2 XML序列化

using System.IO;
using System.Xml.Serialization;

public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Sex { get; set; }
}

// 序列化
public void ToXML()
{
    People people = new People()
    {
        Name = "吴亦凡",
        Age = 18,
        Sex = "男"
    };

    FileStream fs = new FileStream("1.xml", FileMode.Create);
    StreamWriter sw = new StreamWriter(fs);
    XmlSerializer serializer = new XmlSerializer(typeof(People));
    serializer.Serialize(sw, people);
    sw.Close();
    fs.Close();
}

// 反序列化
public void FromXML()
{
    FileStream fs = new FileStream("1.xml", FileMode.Open);
    StreamReader sr = new StreamReader(fs);
    XmlSerializer serializer = new XmlSerializer(typeof(People));
    People people = serializer.Deserialize(sr) as People;
    Console.WriteLine(people.Name);
}

4.3 XML文档操作(XmlDocument)

using System.Xml;

private void button1_Click(object sender, EventArgs e)
{
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(@"XMLFile1.xml");
    
    XmlNode rootNode = xmlDoc.DocumentElement;

    foreach (XmlNode node in rootNode.ChildNodes)
    {
        if (node.Name == "Student")
        {
            Student student = new Student();
            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                    case "StuName":
                        student.StuName = childNode.InnerText;
                        break;
                    case "StuAge":
                        student.StuAge = int.Parse(childNode.InnerText);
                        break;
                }
            }
        }
    }
}

4.4 XmlDocument常用属性与方法

对象 属性/方法 说明
XmlDocument DocumentElement 获取根节点
XmlDocument ChildNodes 获取所有子节点
XmlDocument Load() 加载XML文件
XmlNode InnerText 获取节点内容
XmlNode Name 获取节点名称
XmlNode ChildNodes 获取子节点集合

七、INI文件操作

7.1 INI文件格式

INI是Windows传统配置文件格式:

[Database]
Server=127.0.0.1
Port=3306
Username=root
Password=123456

[Logging]
Level=INFO
File=/var/log/myapp.log

[相机1]
曝光=50
亮度=100

特点:

  • 由节(Section)和键值对组成
  • 所有值都是字符串类型
  • 结构简单,易于维护

7.2 INI文件读写实现

通过调用Windows API实现INI文件操作:

using System.Runtime.InteropServices;
using System.Configuration;

public class FileIni
{
    private static string filePath = ConfigurationManager.AppSettings["InIFilePath"].ToString();

    // 写入INI文件
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool WritePrivateProfileString(
        string lpAppName, 
        string lpKeyName, 
        string lpString, 
        string lpFileName
    );

    // 读取INI文件
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern uint GetPrivateProfileString(
        string lpAppName, 
        string lpKeyName, 
        string lpDefault, 
        StringBuilder lpReturnedString, 
        uint nSize, 
        string lpFileName
    );

    /// <summary>
    /// 写入INI文件
    /// </summary>
    /// <param name="section">节名称</param>
    /// <param name="key">键名</param>
    /// <param name="value">键值</param>
    public static void Write(string section, string key, string value)
    {
        WritePrivateProfileString(section, key, value, filePath);
    }

    /// <summary>
    /// 读取INI文件
    /// </summary>
    /// <param name="section">节名称</param>
    /// <param name="key">键名</param>
    /// <returns>键值</returns>
    public static string Read(string section, string key)
    {
        StringBuilder sb = new StringBuilder();
        GetPrivateProfileString(section, key, "", sb, 255, filePath);
        return sb.ToString();
    }
}

7.3 App.config配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <appSettings>
        <add key="InIFilePath" value="config.ini" />
    </appSettings>
</configuration>

八、CSV文件操作

8.1 CSV格式简介

CSV(Comma Separated Values)是逗号分隔的纯文本格式:

姓名,年龄,性别
小明,20,男
小红,18,女
小华,19,女

8.2 CSV读写示例

using System.IO;

// 写入CSV
private void WriteCSV()
{
    List<string> lines = new List<string>();
    lines.Add("姓名,年龄,性别");
    lines.Add("小明,20,男");
    lines.Add("小红,18,女");
    
    File.WriteAllLines("data.csv", lines, Encoding.Default);
}

// 读取CSV
private void ReadCSV()
{
    string[] lines = File.ReadAllLines("data.csv", Encoding.Default);
    
    foreach (string line in lines)
    {
        string[] values = line.Split(',');
        string name = values[0];
        int age = int.Parse(values[1]);
        string sex = values[2];
    }
}

九、序列化方式对比

方式 优点 缺点 适用场景
二进制序列化 效率高、支持复杂对象 文件不可读、版本兼容差 程序内部数据持久化
JSON序列化 轻量、跨平台、可读性好 需要第三方库 数据交换、API接口
XML序列化 结构化、跨平台、可扩展 体积大、解析慢 配置文件、WebService
INI文件 结构简单、易于维护 功能有限、无类型 应用程序配置
CSV文件 通用、兼容性好 无结构信息 表格数据、数据导出

更多推荐