c#入门详解(刘铁锰)06 - 数据持久化:TXT文本保存、序列化与反序列化(附详细源码)

之前写过一篇,但现在看来已经过时了,所以重新进行了重构

c#-对象的txt保存、序列化和反序列化

demo源码可到公众文章上百度网盘链接自取:

https://mp.weixin.qq.com/s/smm6m7gpDlUy0OjRWorP-A

一、什么是数据持久化

是指将内存中的对象数据保存到存储介质(如文件、数据库)的过程,以便后续重新读取使用。当我们关闭应用程序后,内存中的数据会丢失,而持久化技术可以确保数据长期保存。本文介绍三种实现数据持久化的方法:文本文件保存二进制序列化JSON序列化

为什么需要数据持久化?想象一下,你要进行产品计数。如果没有持久化功能,每次程序关闭后,所有计数数据都会丢失,再次打开又是从0开始计数。而通过持久化技术,这些数据可以永久保存,方便后续查询和修改

之前写的demo在序列化部分使用了已过时且不安全的BinaryFormatter。下面是 System.Text.Json 进行重构的版本,

二、准备工作:创建项目和界面

做一个车辆生产管理的记录模块

控件名称:

复制代码
车型:[txtName]       保存文本:[bitSavetxt]
生产日期:[txtManufacture] 读取文本:[btnReadtxt]
车号:[txtID]           JSON序列化:[btnSerializable]
结果:[txtResult]       JSON反序列化:[btnDeserializable]

三、创建数据模型类

数据模型类是持久化的基础,定义要保存数据的结构。

cs 复制代码
public class Cars

{

    public string Name { get; set; }

    public string Result { get; set; }

    public short ID { get; set; }

    public DateTime Manufacture { get; set; }

}

四、方法一:文本文件保存与读取

文本文件保存是最基础的数据持久化方式,它将对象的各个属性转换为文本格式,逐行保存到文件中。

保存到文本文件

cs 复制代码
private void bitSavetxt_Click(object sender, EventArgs e)

{

    // 封装数据:从界面文本框获取数据并创建Cars对象

    Cars objCars = new Cars()

    {

        Name = this.txtName.Text.Trim(),

        Result = this.txtResult.Text.Trim(),

        ID = Convert.ToInt16(this.txtID.Text.Trim()),

        Manufacture = Convert.ToDateTime(this.txtManufacture.Text.Trim())

    };



    // 使用using语句自动管理资源,确保文件流正确关闭

    // 

    try

    {

        using (FileStream fs = new FileStream("objCars.txt", FileMode.Create))

        using (StreamWriter sw = new StreamWriter(fs))

        {

            // 将对象属性逐行写入文件

            sw.WriteLine(objCars.Name);

            sw.WriteLine(objCars.Manufacture);

            sw.WriteLine(objCars.ID);

            sw.WriteLine(objCars.Result);

        }

        MessageBox.Show("数据保存成功!");

    }

    catch (IOException ex) // 捕获文件操作可能出现的IOException[10](@ref)

    {

        MessageBox.Show($"文件操作错误:{ex.Message}");

    }

    catch (Exception ex) // 捕获其他异常

    {

        MessageBox.Show($"发生错误:{ex.Message}");

    }

}

从文本文件读取

cs 复制代码
 // 从文本文件读取

   private void btnReadtxt_Click(object sender, EventArgs e)

   {

       if (!File.Exists("objCars.txt"))

       {

           MessageBox.Show("文件不存在,请先保存数据。");

           return;

       }



       try

       {

           using (FileStream fs = new FileStream("objCars.txt", FileMode.Open))

           using (StreamReader sr = new StreamReader(fs, Encoding.UTF8)) // 指定编码,与写入一致

           {

               Cars objCars = new Cars();



               // 读取并赋值,顺序必须与写入时完全一致

               objCars.Name = sr.ReadLine() ?? ""; // 处理可能读取到null的情况

               string manufactureString = sr.ReadLine();

               string idString = sr.ReadLine();

               objCars.Result = sr.ReadLine() ?? "";



               // 安全地转换日期和数字

               if (DateTime.TryParse(manufactureString, out DateTime manufactureDate))

               {

                   objCars.Manufacture = manufactureDate;

               }

               else

               {



                   MessageBox.Show("生产日期格式不正确,使用默认值(现在日期)。");

                   objCars.Manufacture = DateTime.Now; // 设置当前日期为默认值



               }



               if (short.TryParse(idString, out short id))

               {

                   objCars.ID = id;

               }

               else

               {



                   MessageBox.Show("编号格式不正确,无法解析,使用默认值!");

                   objCars.ID = 1; //设置 ID 默认值为1



               }

               // 将读取的数据显示在界面

               this.txtName.Text = objCars.Name;

               this.txtManufacture.Text = objCars.Manufacture.ToLongDateString();

               this.txtID.Text = objCars.ID.ToString();

               this.txtResult.Text = objCars.Result;

           }

       }

       catch (Exception ex)

       {

           MessageBox.Show($"读取文件时发生错误:{ex.Message}");

       }

   }

文本保存优缺点

  • 优点:生成的文件人类可读,易于调试和手动修改

  • 缺点:需要手动处理每个属性的保存和读取(要注意顺序),数据类型转换容易出错

五、方法二:JSON序列化(.NET官方推荐使用)

JSON序列化是最常用的方法,它生成我们可读的文本格式,且安全性高,使用System.Text.Json库。

引入System.Text.Json命名空间

确保你的项目已引用System.Text.Json(.NET Core 3.0+或.NET 5+以上版本默认包含,不用添加)。

JSON序列化实现

cs 复制代码
private void btnSerializable_Click(object sender, EventArgs e)

{

    try

    {

        // 封装数据

        Cars objCars = new Cars()

        {

            Name = this.txtName.Text.Trim(),

            Result = this.txtResult.Text.Trim(),

            ID = Convert.ToInt16(this.txtID.Text.Trim()),

            Manufacture = Convert.ToDateTime(this.txtManufacture.Text.Trim())

        };



        // 创建JSON序列化选项,配置缩进以便阅读

        var options = new JsonSerializerOptions 

        { 

            WriteIndented = true 

        };



        // 使用System.Text.Json将对象序列化为JSON字符串

        string jsonString = JsonSerializer.Serialize(objCars, options);



        // 将JSON字符串写入文件

        File.WriteAllText("objCars.json", jsonString);



        MessageBox.Show("JSON序列化成功!");

    }

    catch (Exception ex)

    {

        MessageBox.Show($"序列化过程中发生错误:{ex.Message}");

    }

}

JSON反序列化实现

cs 复制代码
private void btnDeserializable_Click(object sender, EventArgs e)

  {

      try

      {

          // 检查文件是否存在

          if (!File.Exists("objCars.json"))

          {

              MessageBox.Show("未找到JSON文件,请先执行序列化操作。");

              return;

          }



          // 从文件中读取JSON字符串

          string jsonString = File.ReadAllText("objCars.json");



          // 将JSON字符串反序列化为Cars对象

          Cars objCars = JsonSerializer.Deserialize<Cars>(jsonString);



          // 将数据显示在界面

          this.txtName.Text = objCars.Name;

          this.txtManufacture.Text = objCars.Manufacture.ToLongDateString();

          this.txtID.Text = objCars.ID.ToString();

          this.txtResult.Text = objCars.Result;



          MessageBox.Show("JSON反序列化成功!");

      }

      catch (JsonException jsonEx)

      {

          MessageBox.Show($"反序列化失败,JSON格式错误:{jsonEx.Message}");

      }

      catch (Exception ex)

      {

          MessageBox.Show($"反序列化过程中发生错误:{ex.Message}");

      }

  }

六、方法三:XML序列化(备选方案)

XML序列化是另一种常用的序列化方式,特别适用于需要与旧系统交互或需要严格数据结构的场景。

XML序列化实现

cs 复制代码
private void btnXmlSerialize_Click(object sender, EventArgs e)

 {

     try

     {

         // 封装数据

         Cars objCars = new Cars()

         {

             Name = this.txtName.Text.Trim(),

             Result = this.txtResult.Text.Trim(),

             ID = Convert.ToInt16(this.txtID.Text.Trim()),

             Manufacture = Convert.ToDateTime(this.txtManufacture.Text.Trim())

         };



         // 创建XmlSerializer实例

         XmlSerializer serializer = new XmlSerializer(typeof(Cars));



         // 序列化到文件

         using (FileStream stream = new FileStream("objCars.xml", FileMode.Create))

         {

             serializer.Serialize(stream, objCars);

         }



         MessageBox.Show("XML序列化成功!");

     }

     catch (Exception ex)

     {

         MessageBox.Show($"XML序列化过程中发生错误:{ex.Message}");

     }

 }

XML反序列化实现

cs 复制代码
 private void btnXmlDeserialize_Click(object sender, EventArgs e)

    {

        try

        {

            if (!File.Exists("objCars.xml"))

            {

                MessageBox.Show("未找到XML文件,请先执行XML序列化操作。");

                return;

            }



            // 创建XmlSerializer实例

            XmlSerializer serializer = new XmlSerializer(typeof(Cars));



            // 从XML文件反序列化

            using (FileStream stream = new FileStream("objCars.xml", FileMode.Open))

            {

                Cars objCars = (Cars)serializer.Deserialize(stream);



                // 更新界面

                this.txtName.Text = objCars.Name;

                this.txtManufacture.Text = objCars.Manufacture.ToLongDateString();

                this.txtID.Text = objCars.ID.ToString();

                this.txtResult.Text = objCars.Result;

            }



            MessageBox.Show("XML反序列化成功!");

        }

        catch (Exception ex)

        {

            MessageBox.Show($"XML反序列化过程中发生错误:{ex.Message}");

        }

    }

}

总结:

简单数据且不考虑安全的情况下,txt实现最简单,其他场景推荐JSON,XML做备选。

相关推荐
WWZZ20255 小时前
快速上手大模型:机器学习6(过拟合、正则化)
人工智能·算法·机器学习·计算机视觉·机器人·slam·具身感知
ceclar1235 小时前
C++Lambda表达式
开发语言·c++·算法
WWZZ20255 小时前
快速上手大模型:机器学习5(逻辑回归及其代价函数)
人工智能·算法·机器学习·计算机视觉·机器人·slam·具身感知
二进制coder5 小时前
深入浅出:I²C多路复用器PCA9546详解 - 解决地址冲突,扩展你的I²C总线
c语言·开发语言·单片机
姓刘的哦5 小时前
基于线程池的配电房图像检测
人工智能·计算机视觉·目标跟踪
楼田莉子6 小时前
C++学习:C++11关于类型的处理
开发语言·c++·后端·学习
凤山老林6 小时前
SpringBoot 如何实现零拷贝:深度解析零拷贝技术
java·linux·开发语言·arm开发·spring boot·后端
黄毛火烧雪下6 小时前
ruby 、gem 和 cocoapods的联系与区别
开发语言·ruby·cocoapods
盼哥PyAI实验室7 小时前
Python函数进阶秘籍:闭包、装饰器与作用域全解析(通俗版)
开发语言·python