你辛辛苦苦打了半天史莱姆,攒了一背包东西。关掉程序再打开——什么都没了。因为到目前为止,所有数据都只存在于内存里,断电就消失。

我们需要把数据保存到硬盘上,下次启动时再读回来。这就是序列化(把对象变成可以存储的格式)和文件读写(把数据写入硬盘文件)。

我们今天要学习的内容是,保存与加载,序列化与文件。

1. 什么是序列化?

你要把一辆乐高车寄给远方的朋友。你不能直接把拼好的车塞进信封,而是拆成零件,列个清单,装进盒子。朋友收到后,按照清单重新拼装。

  • 序列化:把对象拆成可传输/存储的格式(如 JSON 字符串)

  • 反序列化:把 JSON 字符串重新组装成对象

JSON 是什么?
JSON 是一种用纯文本表示数据的格式,人和机器都能轻松读懂。

{
    "name": "绿色史莱姆",
    "hp": 30,
    "attackPower": 5
}

2. 把史莱姆变成 JSON 字符串

C# 提供了内置的 JSON 序列化工具 System.Text.Json

第一步,在文件最上面引入命名空间:

using System.Text.Json;

第二步,给要序列化的类加一个标记(只有 public 属性会被序列化):

我们现在把 Slime 类改造一下,使用属性而不是字段(因为 JSON 序列化需要属性):

using System;
using System.Text.Json;

namespace MyGame
{
    class Slime
    {
        public string Name { get; set; }
        public int Hp { get; set; }
        public int AttackPower { get; set; }
        public string DropItem { get; set; }

        public Slime() { }  // 无参构造函数,反序列化时需要

        public Slime(string name, int hp, int attack, string drop)
        {
            Name = name;
            Hp = hp;
            AttackPower = attack;
            DropItem = drop;
        }

        public void ShowInfo()
        {
            Console.WriteLine($"  {Name} | HP:{Hp} | 攻击:{AttackPower} | 掉落:{DropItem}");
        }
    }
}

第三步,序列化一个史莱姆对象:

// 创建一个史莱姆
Slime slime = new Slime("绿色史莱姆", 30, 5, "史莱姆粘液");

// 序列化成 JSON 字符串
string jsonString = JsonSerializer.Serialize(slime);
Console.WriteLine(jsonString);
// 输出:{"Name":"绿色史莱姆","Hp":30,"AttackPower":5,"DropItem":"史莱姆粘液"}

第四步,反序列化——从 JSON 字符串变回对象:

string savedJson = "{\"Name\":\"蓝色史莱姆\",\"Hp\":20,\"AttackPower\":8,\"DropItem\":\"蓝色碎片\"}";

Slime loadedSlime = JsonSerializer.Deserialize<Slime>(savedJson);
loadedSlime.ShowInfo();
// 输出:蓝色史莱姆 | HP:20 | 攻击:8 | 掉落:蓝色碎片

3. 把数据写入文件(保存)

文件读写的核心类在 System.IO 命名空间里。

using System.IO;

// ...

string filePath = "save.txt";

// 1. 创建要保存的数据
Slime mySlime = new Slime("黄金史莱姆", 50, 12, "金币");

// 2. 序列化成 JSON
string json = JsonSerializer.Serialize(mySlime);

// 3. 写入文件
File.WriteAllText(filePath, json);
Console.WriteLine("保存成功!文件路径:" + filePath);

运行后,你的项目文件夹里会多一个 save.txt,打开就能看到 JSON 内容。

4. 从文件读取数据(加载)

string filePath = "save.txt";

// 1. 检查文件是否存在
if (File.Exists(filePath))
{
    // 2. 读取文件内容
    string json = File.ReadAllText(filePath);

    // 3. 反序列化成对象
    Slime loadedSlime = JsonSerializer.Deserialize<Slime>(json);
    loadedSlime.ShowInfo();
}
else
{
    Console.WriteLine("存档文件不存在!");
}

5. 保存一个列表(多个对象)

游戏里你需要保存整队敌人或整个背包,这需要序列化列表。

// 创建一个敌人列表
List<Slime> slimes = new List<Slime>
{
    new Slime("红色史莱姆", 40, 10, "火焰碎片"),
    new Slime("蓝色史莱姆", 25, 6, "冰霜碎片"),
    new Slime("绿色史莱姆", 30, 5, "史莱姆粘液")
};

// 序列化整个列表
string json = JsonSerializer.Serialize(slimes);
File.WriteAllText("slimes.json", json);
Console.WriteLine("敌人列表已保存!");

// 读取列表
string loadedJson = File.ReadAllText("slimes.json");
List<Slime> loadedSlimes = JsonSerializer.Deserialize<List<Slime>>(loadedJson);

Console.WriteLine("\n读取到的敌人列表:");
foreach (Slime s in loadedSlimes)
{
    s.ShowInfo();
}

6. 实战:可存档的背包系统

让我运用本节课所学知识,来升级一下我们的背包系统

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;

namespace MyGame
{
    class Inventory
    {
        private List<string> items;
        private string savePath = "inventory.json";

        public Inventory()
        {
            items = new List<string>();
        }

        public void AddItem(string itemName)
        {
            items.Add(itemName);
            Console.WriteLine("获得物品:" + itemName);
        }

        public void RemoveItem(string itemName)
        {
            if (items.Contains(itemName))
            {
                items.Remove(itemName);
                Console.WriteLine("失去了物品:" + itemName);
            }
            else
            {
                Console.WriteLine("背包里没有" + itemName + "!");
            }
        }

        public void ShowInventory()
        {
            Console.WriteLine("\n=== 当前背包 ===");
            if (items.Count == 0)
            {
                Console.WriteLine("(空)");
            }
            else
            {
                for (int i = 0; i < items.Count; i++)
                {
                    Console.WriteLine("  [" + (i + 1) + "] " + items[i]);
                }
            }
            Console.WriteLine("总物品数:" + items.Count);
        }

        // ★ 保存到文件
        public void Save()
        {
            string json = JsonSerializer.Serialize(items);
            File.WriteAllText(savePath, json);
            Console.WriteLine("背包已保存!");
        }

        // ★ 从文件加载
        public void Load()
        {
            if (File.Exists(savePath))
            {
                string json = File.ReadAllText(savePath);
                items = JsonSerializer.Deserialize<List<string>>(json);
                Console.WriteLine("背包已加载!");
            }
            else
            {
                Console.WriteLine("没有找到存档,使用空背包。");
            }
        }
    }
}

7. 保存整个游戏状态

真实游戏中,你需要保存的不只是背包,而是一个完整的游戏存档。我们来创建一个 GameSaveData 类:

using System.Collections.Generic;

namespace MyGame
{
    // 这个类专门用来保存游戏状态
    class GameSaveData
    {
        public string PlayerName { get; set; }
        public int PlayerHp { get; set; }
        public int PlayerLevel { get; set; }
        public List<string> InventoryItems { get; set; }
        public int SlimeKillCount { get; set; }
    }
}

在 Program.cs 中使用:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;

namespace MyGame
{
    class Program
    {
        static string savePath = "gamesave.json";

        static void Main(string[] args)
        {
            Console.WriteLine("1. 新游戏");
            Console.WriteLine("2. 继续游戏");
            Console.Write("请选择:");
            string choice = Console.ReadLine();

            GameSaveData data;

            if (choice == "2" && File.Exists(savePath))
            {
                // 加载存档
                string json = File.ReadAllText(savePath);
                data = JsonSerializer.Deserialize<GameSaveData>(json);
                Console.WriteLine("\n存档已加载!欢迎回来," + data.PlayerName + "!\n");
            }
            else
            {
                // 新建存档
                data = new GameSaveData
                {
                    PlayerName = "勇者",
                    PlayerHp = 100,
                    PlayerLevel = 1,
                    InventoryItems = new List<string> { "木剑", "生命药水" },
                    SlimeKillCount = 0
                };
                Console.WriteLine("\n新冒险开始!\n");
            }

            // 显示状态
            ShowStatus(data);

            // 模拟一些游戏过程
            Console.WriteLine("\n--- 你打了一只史莱姆 ---");
            data.SlimeKillCount++;
            data.InventoryItems.Add("史莱姆粘液");

            ShowStatus(data);

            // 保存
            string saveJson = JsonSerializer.Serialize(data);
            File.WriteAllText(savePath, saveJson);
            Console.WriteLine("\n游戏已保存!");

            Console.ReadKey();
        }

        static void ShowStatus(GameSaveData data)
        {
            Console.WriteLine("=== 角色状态 ===");
            Console.WriteLine("姓名:" + data.PlayerName);
            Console.WriteLine("血量:" + data.PlayerHp);
            Console.WriteLine("等级:" + data.PlayerLevel);
            Console.WriteLine("击杀数:" + data.SlimeKillCount);
            Console.Write("背包:");
            foreach (string item in data.InventoryItems)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
        }
    }
}

好了,这节课我们学习的知识点较多,我们来总结一下

对象→JSON字符串 JsonSerializer.Serialize(obj)
JSON字符串→对象 JsonSerializer.Deserialize<类型>(json)
写入文件 File.WriteAllText(路径, 内容)
读取文件 File.ReadAllText(路径)
检查文件是否存在

File.Exists(路径)

今天的学习就到这里,关注我,下期更精彩。

更多推荐