概述

什么是数据持久化?

  • 将内存中的数据模型转化为存储模型,以及将存储模型转换为内存中的数据模型
  • 简单来说就是存盘操作

Json是什么?

  • 直译:JavaScript对象简谱
  • 一种轻量化的数据交换格式
  • 可以用于传输数据,本地数据存储和读取

Json与Xml异同

共同点

  • 都是纯文本
  • 都有层级结构
  • 都具有描述性

不同点

  • Json配置简单
  • Json在一些情况读写更快速

Json语法

注释与大多数语言一样

//注释内容
/* 注释内容*/

Json是一种键值对结构,和字典类似

//大括号包裹的就是一个对象
{
    "name":"xiaowan",
    "age":18.0,
    "gender":true,
    "ids":[1,2,3,4],
    "student":[{"name":"a","age":"1","gender":"true"},
              {"name":"b","age":"2","gender":"true"}],
    "itemList":[{"id":2, "num":10}, 
                {"id":3, "num":99},
                {"id":4, "num":55}],
    "itemDic":{ "2":{"id":2, "num":1},
                "3":{"id":3, "num":10}},
    "son":null
}

注意事项

  • 如果数据表示对象那么最外层有大括号
  • 一定是键值对形式
  • 键一定是字符串格式
  • 键值对用逗号分开
  • 数组用[ ] 包裹
  • 对象用{ } 包裹

Excel转Json

/*
excel
hp  speed   volume  resName scale
4   6   5   Airplane/Airplane1  15
3   7   4   Airplane/Airplane2  15
2   8   3   Airplane/Airplane3  15
10  3   10  Airplane/Airplane4  6
6   5   7   Airplane/Airplane5  10
*/
[
{"hp":4,"speed":6,"volume":5,"resName":"Airplane/Airplane1","scale":15},
{"hp":3,"speed":7,"volume":4,"resName":"Airplane/Airplane2","scale":15},
{"hp":2,"speed":8,"volume":3,"resName":"Airplane/Airplane3","scale":15},
{"hp":10,"speed":3,"volume":10,"resName":"Airplane/Airplane4","scale":6},
{"hp":6,"speed":5,"volume":7,"resName":"Airplane/Airplane5","scale":10}
]

JsonUtlity

JsonUtlity是什么?

  • Unity自带的用于解析Json的公共类
  • 可以将内存中对象序列化为Json格式的字符串
  • 将Json字符串反序列化为类对象

在文件中存取字符串

//需要引入命名空间
using System.IO; 

//存
File.WriteAllText(Application.persistentDataPath + "/Test.json", "要储存的字符串");
//File.WriteAllText(路径(要保证文件夹存在),"字符串");

//取
string str = File.ReadAllText(Application.persistentDataPath + "/Test.json");
//File.ReadAllText(路径);

常用路径:

Application.persistentDataPath

API文档:https://docs.unity3d.com/cn/2018.2/ScriptReference/Application-persistentDataPath.html

  • 包含持久数据目录的路径(只读)。
  • 该值是目录路径;此目录中可以存储每次运行要保留的数据。在 iOS 和 Android 上发布时,persistentDataPath 指向设备上的公共目录。应用程序更新不会擦除此位置中的文件。用户仍然可以直接擦除这些文件。

使用JsonUtlity进行序列化

序列化就是把内存中的数据 存储到硬盘上

//Jsonutility提供了现成的方法将类对象序列化为json字符串
//将转化的json字符串存到jsonString中之后通过字符串写入(WriteAllText)到文件中
string jsonString = JsonUtility.ToJson(对象)
//存数据
File.WriteAllText(Application.persistentDataPath + "/路径", jsonStr);

注意点:

  • float类型序列化时看起来会有一些误差,实际读取时没有问题
  • 自定义类需要加上序列化特性[System.Serializable]
    • [System.Serializable]
      public class Student
      {
          public int age;
          public string name;
          public Student(int age,string name)
          {
              this.age = age;
              this.name = name;
          }
      }
      
  • 想要序列化私有、保护变量 需要加上特性[SerializeField]
    • [SerializeField]
      private int privateI;
      [SerializeField]
      protected int protectedI;
      
  • JsonUtility不支持字典,因此无法被序列化
  • JsonUtlity存储null的对象,json文件获取到的不会是null,而是对象默认值的数据

使用JsonUtlity进行反序列化

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

//读取文件中的 Json字符串
jsonStr = File.ReadAllText(Application.persistentDataPath + "/Test.json");
//将Json字符串内容通过反序列化转换成类对象(两个重载方法)
className t1 = JsonUtility.FromJson(jsonStr, typeof(className)) as className;
className t2 = JsonUtility.FromJson<className>(jsonStr);//推荐使用

JsonUtlity注意事项

  • 如果Json中数据少了,读取到内存中类对象中时不会报错
  • JsonUtlity无法直接读取数据集合,需要在json文件中包裹一层对象("对象名":[...])
  • Json文档编码格式必须是UTF-8,否则会报错

LitJson

LitJson是什么?

  • LitJson是一个第三方库用于处理Json的序列化与反序列化
  • LitJson是C#编写的,体积小、速度快、易于使用
  • 下载地址:https://github.com/LitJSON/litjson
  • 拷贝src/LitJson到工程中即可使用

使用LitJson进行序列化

//引入命名空间
using LitJson;
//序列化
string jsonStr = JsonMapper.ToJson(对象);
//存数据
File.WriteAllText(Application.persistentDataPath + "/path", jsonStr);
  • 不需要增加[SerializeField]特性
  • 不能序列化私有变量
  • 支持字典,建议使键使用string数据类型
  • LitJson可以准确保存null类型

使用LitJson进行反序列化

jsonStr = File.ReadAllText(Application.persistentDataPath + "/path.json");
//JsonData是LitJson提供的类对象 
//使用键值对的形式去访问其中的内容
JsonData data = JsonMapper.ToObject(jsonStr);
print(data["name"]);
print(data["age"]);
//通过泛型转换,建议使用
className t2 = JsonMapper.ToObject<className>(jsonStr);
  • 类结构需要无参构造函数,否则反序列化时报错
  • 字典虽然支持 但是键在使用为数值时会有问题,需要使用字符串类型

LitJson注意事项

  • LitJson可以直接读取数据集合
    • jsonStr = File.ReadAllText(Application.streamingAssetsPath + "/RoleInfo.json");
      RoleInfo2[] arr = JsonMapper.ToObject<RoleInfo2[]>(jsonStr);
      List<RoleInfo2> list = JsonMapper.ToObject<List<RoleInfo2>>(jsonStr);
      jsonStr = File.ReadAllText(Application.streamingAssetsPath + "/Dic.json");
      Dictionary<string, int> dicTest = JsonMapper.ToObject<Dictionary<string, int>>(jsonStr);
      
  • 文本编码格式需要是UTF-8,否则无法加载

练习:Json数据管理类

代码

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

/// <summary>
/// 序列化和反序列化Json时  使用的是哪种方案
/// </summary>
public enum JsonType
{
    JsonUtlity,
    LitJson,
}

/// <summary>
/// Json数据管理类 主要用于进行 Json的序列化存储到硬盘 和 反序列化从硬盘中读取到内存中
/// </summary>
public class JsonMgr
{
    private static JsonMgr instance = new JsonMgr();
    public static JsonMgr Instance => instance;

    private JsonMgr() { }

    //存储Json数据 序列化
    public void SaveData(object data, string fileName, JsonType type = JsonType.LitJson)
    {
        //确定存储路径
        string path = Application.persistentDataPath + "/" + fileName + ".json";
        //序列化 得到Json字符串
        string jsonStr = "";
        switch (type)
        {
            case JsonType.JsonUtlity:
                jsonStr = JsonUtility.ToJson(data);
                break;
            case JsonType.LitJson:
                jsonStr = JsonMapper.ToJson(data);
                break;
        }
        //把序列化的Json字符串 存储到指定路径的文件中
        File.WriteAllText(path, jsonStr);
    }

    //读取指定文件中的 Json数据 反序列化
    public T LoadData<T>(string fileName, JsonType type = JsonType.LitJson) where T : new()
    {
        //确定从哪个路径读取
        //首先先判断 默认数据文件夹中是否有我们想要的数据 如果有 就从中获取
        string path = Application.streamingAssetsPath + "/" + fileName + ".json";
        //先判断 是否存在这个文件
        //如果不存在默认文件 就从 读写文件夹中去寻找
        if(!File.Exists(path))
            path = Application.persistentDataPath + "/" + fileName + ".json";
        //如果读写文件夹中都还没有 那就返回一个默认对象
        if (!File.Exists(path))
            return new T();

        //进行反序列化
        string jsonStr = File.ReadAllText(path);
        //数据对象
        T data = default(T);
        switch (type)
        {
            case JsonType.JsonUtlity:
                data = JsonUtility.FromJson<T>(jsonStr);
                break;
            case JsonType.LitJson:
                data = JsonMapper.ToObject<T>(jsonStr);
                break;
        }

        //把对象返回出去
        return data;
    }
}

使用

//存数据
JsonMgr.Instance.SaveData(objName,"path",JsonType.emum(可选));
//取数据
className t1 =JsonMgr.Instance.LoadData<ClassName>("path",JsonType.emum(可选));

百度网盘:提取码:aqja