4.JsonUtility

4.CSharp操作Json-JsonUtility


4.1 知识点

JsonUtlity是什么

JsonUtlity 是Unity自带的用于解析Json的公共类。

JsonUtlity可以:

  1. 将内存中对象序列化为Json格式的字符串。
  2. 将Json字符串反序列化为类对象。

必备知识点—在文件中存读字符串

File.WriteAllText方法 存储字符串到指定路径文件中

//File类中的WriteAllText方法 存储字符串到指定路径文件中
//第一个参数 填写的是 存储的路径
//第二个参数 填写的是 存储的字符串内容
//注意:第一个参数 必须是存在的文件路径 如果没有对应文件夹 会报错
File.WriteAllText(Application.persistentDataPath + "/Test.json", "林文韬存储的json文件");
print(Application.persistentDataPath);//C:/Users/78529/AppData/LocalLow/DefaultCompany/Json_Teach

File.ReadAllText方法 在指定路径文件中读取字符串

//File类中的ReadAllText方法 在指定路径文件中读取字符串
string str = File.ReadAllText(Application.persistentDataPath + "/Test.json");
print(str);//林文韬存储的json文件

使用JsonUtlity进行序列化

序列化:把内存中的数据存储到硬盘上。为此,需要准备一个类和对象实例。

准备一个类和对象实例

测试类
[System.Serializable]
public class Student
{
    public int age;
    public string name;

    public Student(int age, string name)
    {
        this.age = age;
        this.name = name;
    }
}

public class MrTao
{
    public string name;
    public int age;
    public bool sex;
    public float testF;
    public double testD;

    public int[] ids;
    public List<int> ids2;
    public Dictionary<int, string> dic;
    public Dictionary<string, string> dic2;

    public Student s1;
    public List<Student> s2s;

    [SerializeField]
    private int privateI = 1;
    [SerializeField]
    protected int protectedI = 2;
}
实例
MrTao t = new MrTao();
t.name = "韬老狮";
t.age = 18;
t.sex = false;
t.testF = 1.4f;
t.testD = 1.4;

t.ids = new int[] { 1, 2, 3, 4 };
t.ids2 = new List<int>() { 1, 2, 3 };
t.dic = new Dictionary<int, string>() { { 1, "123" }, { 2, "234" } };
t.dic2 = new Dictionary<string, string>() { { "1", "123" }, { "2", "234" } };

t.s1 = null;//new Student(1, "小红");
t.s2s = new List<Student>() { new Student(2, "小明"), new Student(3, "小强") };

JsonUtility.ToJson方法 序列化对象

//JsonUtility类中的ToJson方法 序列化对象
//Jsonutility提供了线程的方法 可以把类对象 序列化为 json字符串
//生成对象的公共字段的 JSON 表示形式。
//JsonUtility.ToJson(对象)
string jsonStr = JsonUtility.ToJson(t);
File.WriteAllText(Application.persistentDataPath + "/MrTao.json", jsonStr);

JsonUtlity序列化时注意事项

  • float序列化时看起来会有一些误差。
  • 自定义类需要加上序列化特性[System.Serializable]。
  • 想要序列化私有变量,需要加上特性[SerializeField]。
  • JsonUtility不支持字典。
  • JsonUtlity存储null对象不会是null,而是默认值的数据。

查看序列化后的json文件

{"name":"韬老狮","age":18,"sex":false,"testF":1.399999976158142,"testD":1.4,"ids":[1,2,3,4],"ids2":[1,2,3],"s1":{"age":0,"name":""},"s2s":[{"age":2,"name":"小明"},{"age":3,"name":"小强"}],"privateI":1,"protectedI":2}

使用JsonUtlity进行反序列化

反序列化:把硬盘上的数据读取到内存中。

//读取文件中的 Json字符串
jsonStr = File.ReadAllText(Application.persistentDataPath + "/MrTao.json");

JsonUtility.FromJson方法 反序列化对象

//JsonUtility类中的FromJson方法 反序列化对象
//通过 JSON 表示形式创建对象。
//JsonUtility.FromJson(字符串)
//使用Json字符串内容 转换成类对象
MrTao t2 = JsonUtility.FromJson(jsonStr, typeof(MrTao)) as MrTao;
MrTao t3 = JsonUtility.FromJson<MrTao>(jsonStr);

JsonUtlity反序列化时注意事项

如果Json中数据少了,读取到内存中类对象中时不会报错。

JsonUtility注意事项

JsonUtlity无法直接读取数据集合,比如直接读取List或数组会报错。

[System.Serializable]
public class RoleInfo
{
    public int hp;
    public int speed;
    public int volume;
    public string resName;
    public int scale;
}

//JsonUtlity无法直接读取数据集合 比如直接读取List或数组 会报错
string jsonStr1 = File.ReadAllText(Application.streamingAssetsPath + "/RoleInfo.json");
print(jsonStr1);
//List<RoleInfo> roleInfoList = JsonUtility.FromJson<List<RoleInfo>>(jsonStr1);//报错

用对象包裹一层List同时修改json文件也用对象包裹List就不会报错。

public class RoleData
{
    public List<RoleInfo> list;
}

string jsonStr2 = File.ReadAllText(Application.streamingAssetsPath + "/RoleInfo2.json");
print(jsonStr2);
RoleData data = JsonUtility.FromJson<RoleData>(jsonStr2);

文本编码格式需要是UTF-8,否则无法加载。如果修改了文件格式不是UTF-8,会报错。

总结

  • 必备知识点——File存读字符串的方法ReadAllText和WriteAllText。
  • JsonUtlity提供的序列化反序列化方法ToJson和FromJson。
  • 自定义类需要加上序列化特性[System.Serializable]。
  • 私有保护成员需要加上[SerializeField]。
  • JsonUtlity不支持字典。
  • JsonUtlity不能直接将数据反序列化为数据集合。
  • Json文档编码格式必须是UTF-8。

4.2 知识点代码

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

[System.Serializable]
public class Student
{
    public int age;
    public string name;

    public Student(int age, string name)
    {
        this.age = age;
        this.name = name;
    }
}

public class MrTao
{
    public string name;
    public int age;
    public bool sex;
    public float testF;
    public double testD;

    public int[] ids;
    public List<int> ids2;
    public Dictionary<int, string> dic;
    public Dictionary<string, string> dic2;

    public Student s1;
    public List<Student> s2s;

    [SerializeField]
    private int privateI = 1;
    [SerializeField]
    protected int protectedI = 2;
}

public class RoleData
{
    public List<RoleInfo> list;
}

[System.Serializable]
public class RoleInfo
{
    public int hp;
    public int speed;
    public int volume;
    public string resName;
    public int scale;
}

public class Lesson04_CSharp读取存储Json文件_JsonUtility : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 JsonUtlity是什么?
        //JsonUtlity 是Unity自带的用于解析Json的公共类
        //它可以
        //1.将内存中对象序列化为Json格式的字符串
        //2.将Json字符串反序列化为类对象
        #endregion

        #region 知识点二 必备知识点——在文件中存读字符串

        //File类中的WriteAllText方法 存储字符串到指定路径文件中
        //第一个参数 填写的是 存储的路径
        //第二个参数 填写的是 存储的字符串内容
        //注意:第一个参数 必须是存在的文件路径 如果没有对应文件夹 会报错
        File.WriteAllText(Application.persistentDataPath + "/Test.json", "林文韬存储的json文件");
        print(Application.persistentDataPath);//C:/Users/78529/AppData/LocalLow/DefaultCompany/Json_Teach

        //File类中的ReadAllText方法 在指定路径文件中读取字符串
        string str = File.ReadAllText(Application.persistentDataPath + "/Test.json");
        print(str);//林文韬存储的json文件

        #endregion

        #region 知识点三 使用JsonUtlity进行序列化

        //序列化:把内存中的数据 存储到硬盘上

        //准备一个类和对象实例
        MrTao t = new MrTao();
        t.name = "韬老狮";
        t.age = 18;
        t.sex = false;
        t.testF = 1.4f;
        t.testD = 1.4;

        t.ids = new int[] { 1, 2, 3, 4 };
        t.ids2 = new List<int>() { 1, 2, 3 };
        t.dic = new Dictionary<int, string>() { { 1, "123" }, { 2, "234" } };
        t.dic2 = new Dictionary<string, string>() { { "1", "123" }, { "2", "234" } };

        t.s1 = null;//new Student(1, "小红");
        t.s2s = new List<Student>() { new Student(2, "小明"), new Student(3, "小强") };

        //JsonUtility类中的ToJson方法 序列化对象
        //Jsonutility提供了线程的方法 可以把类对象 序列化为 json字符串
        //生成对象的公共字段的 JSON 表示形式。
        //JsonUtility.ToJson(对象)
        string jsonStr = JsonUtility.ToJson(t);
        File.WriteAllText(Application.persistentDataPath + "/MrTao.json", jsonStr);

        //JsonUtlity进行序列化时注意事项:
        //1.float序列化时看起来会有一些误差
        //2.自定义类需要加上序列化特性[System.Serializable] 最外层存储的对象可以不用加 但是最好也加上
        //3.想要序列化私有变量 需要加上特性[SerializeField]
        //4.JsonUtility不支持字典
        //5.JsonUtlity存储null对象不会是null 而是默认值的数据
        #endregion

        #region 知识点四 使用JsonUtlity进行反序列化

        //反序列化:把硬盘上的数据 读取到内存中

        //读取文件中的 Json字符串
        jsonStr = File.ReadAllText(Application.persistentDataPath + "/MrTao.json");

        //JsonUtility类中的FromJson方法 反序列化对象
        //通过 JSON 表示形式创建对象。
        //JsonUtility.FromJson(字符串)
        //使用Json字符串内容 转换成类对象
        MrTao t2 = JsonUtility.FromJson(jsonStr, typeof(MrTao)) as MrTao;
        MrTao t3 = JsonUtility.FromJson<MrTao>(jsonStr);

        //JsonUtlity进行反序列化时注意事项:如果Json中数据少了,读取到内存中类对象中时不会报错
        #endregion

        #region 知识点五 JsonUtility中的注意事项

        //JsonUtlity无法直接读取数据集合 比如直接读取List或数组 会报错
        string jsonStr1 = File.ReadAllText(Application.streamingAssetsPath + "/RoleInfo.json");
        print(jsonStr1);
        //List<RoleInfo> roleInfoList = JsonUtility.FromJson<List<RoleInfo>>(jsonStr1);

        //用对象包裹一层List同时修改json文件也用对象包裹List 就不会报错了
        string jsonStr2 = File.ReadAllText(Application.streamingAssetsPath + "/RoleInfo2.json");
        print(jsonStr2);
        RoleData data = JsonUtility.FromJson<RoleData>(jsonStr2);

        //2.文本编码格式需要时UTF-8 不然无法加载
        #endregion

        #region 总结
        //1.必备知识点 —— File存读字符串的方法 ReadAllText和WriteAllText
        //2.JsonUtlity提供的序列化反序列化方法 ToJson 和 FromJson
        //3.自定义类需要加上序列化特性[System.Serializable]
        //4.私有保护成员 需要加上[SerializeField]
        //5.JsonUtlity不支持字典
        //6.JsonUtlity不能直接将数据反序列化为数据集合
        //7.Json文档编码格式必须是UTF-8
        #endregion
    }

}

4.3 练习题

有一个玩家数据类,为该类写一个方法结合JsonUtility知识点,完成对象的序列化和反序列化

声明物品类和玩家信息类,注意自定义类和私有字段要添加特性
/// <summary>
/// 物品类
/// </summary>
[System.Serializable]
public class Item
{
    public int id;       // 物品ID
    public int num;      // 物品数量

    public Item(int id, int num)
    {
        this.id = id;
        this.num = num;
    }
}

/// <summary>
/// 玩家信息类
/// </summary>
public class PlayerInfo
{
    public string name;                      // 玩家姓名
    public int atk;                          // 玩家攻击力
    public int def;                          // 玩家防御力
    public float moveSpeed;                  // 玩家移动速度
    public double roundSpeed;                // 玩家旋转速度
    public Item weapon;                      // 玩家武器信息
    public List<int> listInt;                // 整型列表
    public List<Item> itemList;              // 物品列表
    public Dictionary<int, Item> itemDic;    // 物品字典,以物品ID作为键
    public Dictionary<string, Item> itemDic2;// 物品字典,以字符串型的物品ID作为键
    [SerializeField]
    private int privateI = 1;                // 私有整数字段
    [SerializeField]
    protected int protectedI = 2;            // 受保护整数字段
}
创建一个玩家对象并设置其属性
// 创建一个玩家对象并设置其属性
PlayerInfo player = new PlayerInfo();
player.name = "韬老狮";
player.atk = 11;
player.def = 5;
player.moveSpeed = 20.5f;
player.roundSpeed = 21.4f;

// 创建一个武器对象并将其赋值给玩家的武器属性
player.weapon = new Item(1, 1);

// 创建一个整型列表并将其赋值给玩家的整型列表属性
player.listInt = new List<int>() { 1, 2, 3, 4, 5 };

// 创建一个物品列表并将其赋值给玩家的物品列表属性
player.itemList = new List<Item>() { new Item(1, 99), new Item(2, 44) };

// 创建一个物品字典并将其赋值给玩家的物品字典属性(以物品ID作为键)
player.itemDic = new Dictionary<int, Item>() { { 1, new Item(1, 12) }, { 2, new Item(2, 22) } };

// 创建一个物品字典并将其赋值给玩家的物品字典属性(以字符串型的物品ID作为键)
player.itemDic2 = new Dictionary<string, Item>() { { "1", new Item(1, 12) }, { "2", new Item(2, 22) } };
创建序列化对象并保存为JSON文件的方法并调用
/// <summary>
/// 序列化对象并保存为JSON文件
/// </summary>
/// <param name="player">要序列化的玩家对象</param>
/// <param name="path">保存的文件路径</param>
public void SaveData(PlayerInfo player, string path)
{
    // 将玩家对象序列化为JSON字符串
    string jsonStr = JsonUtility.ToJson(player);

    // 打印持久化数据的路径
    print(Application.persistentDataPath);

    // 将JSON字符串写入指定路径的文件中
    File.WriteAllText(Application.persistentDataPath + "/" + path + ".json", jsonStr);
}

// 将玩家对象保存为JSON文件
SaveData(player, "PlayerInfo");
创建加载JSON文件并反序列化为玩家对象的方法并调用
/// <summary>
/// 加载JSON文件并反序列化为玩家对象
/// </summary>
/// <param name="path">要加载的文件路径</param>
/// <returns>反序列化后的玩家对象</returns>
public PlayerInfo LoadData(string path)
{
    // 读取JSON文件内容
    string jsonStr = File.ReadAllText(Application.persistentDataPath + "/" + path + ".json");

    // 将JSON字符串反序列化为玩家对象
    return JsonUtility.FromJson<PlayerInfo>(jsonStr);
}



// 加载JSON文件并将其反序列化为玩家对象
PlayerInfo player2 = LoadData("PlayerInfo");

4.4 练习题代码

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

/// <summary>
/// 物品类
/// </summary>
[System.Serializable]
public class Item
{
    public int id;       // 物品ID
    public int num;      // 物品数量

    public Item(int id, int num)
    {
        this.id = id;
        this.num = num;
    }
}

/// <summary>
/// 玩家信息类
/// </summary>
public class PlayerInfo
{
    public string name;                      // 玩家姓名
    public int atk;                          // 玩家攻击力
    public int def;                          // 玩家防御力
    public float moveSpeed;                  // 玩家移动速度
    public double roundSpeed;                // 玩家旋转速度
    public Item weapon;                      // 玩家武器信息
    public List<int> listInt;                // 整型列表
    public List<Item> itemList;              // 物品列表
    public Dictionary<int, Item> itemDic;    // 物品字典,以物品ID作为键
    public Dictionary<string, Item> itemDic2;// 物品字典,以字符串型的物品ID作为键
    [SerializeField]
    private int privateI = 1;                // 私有整数字段
    [SerializeField]
    protected int protectedI = 2;            // 受保护整数字段
}


public class Lesson04_练习题 : MonoBehaviour
{
    #region 练习题一
    //有一个玩家数据类
    //请为该类写一个方法结合JsonUtility知识点
    //完成对象的序列化和反序列化

    /// <summary>
    /// 当游戏开始时调用的方法
    /// </summary>
    void Start()
    {
        // 创建一个玩家对象并设置其属性
        PlayerInfo player = new PlayerInfo();
        player.name = "韬老狮";
        player.atk = 11;
        player.def = 5;
        player.moveSpeed = 20.5f;
        player.roundSpeed = 21.4f;

        // 创建一个武器对象并将其赋值给玩家的武器属性
        player.weapon = new Item(1, 1);

        // 创建一个整型列表并将其赋值给玩家的整型列表属性
        player.listInt = new List<int>() { 1, 2, 3, 4, 5 };

        // 创建一个物品列表并将其赋值给玩家的物品列表属性
        player.itemList = new List<Item>() { new Item(1, 99), new Item(2, 44) };

        // 创建一个物品字典并将其赋值给玩家的物品字典属性(以物品ID作为键)
        player.itemDic = new Dictionary<int, Item>() { { 1, new Item(1, 12) }, { 2, new Item(2, 22) } };

        // 创建一个物品字典并将其赋值给玩家的物品字典属性(以字符串型的物品ID作为键)
        player.itemDic2 = new Dictionary<string, Item>() { { "1", new Item(1, 12) }, { "2", new Item(2, 22) } };

        // 将玩家对象保存为JSON文件
        SaveData(player, "PlayerInfo");

        // 加载JSON文件并将其反序列化为玩家对象
        PlayerInfo player2 = LoadData("PlayerInfo");
    }

    /// <summary>
    /// 序列化对象并保存为JSON文件
    /// </summary>
    /// <param name="player">要序列化的玩家对象</param>
    /// <param name="path">保存的文件路径</param>
    public void SaveData(PlayerInfo player, string path)
    {
        // 将玩家对象序列化为JSON字符串
        string jsonStr = JsonUtility.ToJson(player);

        // 打印持久化数据的路径
        print(Application.persistentDataPath);

        // 将JSON字符串写入指定路径的文件中
        File.WriteAllText(Application.persistentDataPath + "/" + path + ".json", jsonStr);
    }

    /// <summary>
    /// 加载JSON文件并反序列化为玩家对象
    /// </summary>
    /// <param name="path">要加载的文件路径</param>
    /// <returns>反序列化后的玩家对象</returns>
    public PlayerInfo LoadData(string path)
    {
        // 读取JSON文件内容
        string jsonStr = File.ReadAllText(Application.persistentDataPath + "/" + path + ".json");

        // 将JSON字符串反序列化为玩家对象
        return JsonUtility.FromJson<PlayerInfo>(jsonStr);
    }

    #endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏