json数据持久化--JsonUtility

180 阅读5分钟

数据持久化

  • 将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型
  • 是一种存盘操作

what(Json是什么?)

  • Json是Javascript的对象简谱
  • 一种轻量化的数据交换格式
  • 用于传输数据,本地存储和读取数据

why(为什么使用Json)

  • json配置简单
  • json读写更为快速

how(怎么使用Json)

Unity中使用JsonUtlity,关于JsonUtility,描述如下:

  1. Unity自带的用于解析Json的公共类
  2. 可以将内存中的对象序列化为Json格式的字符串
  3. 可以将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, 该路径包含持久数据目录的路径(只读),- 该值是目录路径;此目录中可以存储每次运行要保留的数据。在 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);//推荐使用

注意事项

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

项目持久化练习

1.实体类代码

using UnityEngine;

/*
 JSON是一种轻量级的数据交换和存储格式

可以用于对数据的设备(如手机的本地存储)和向Web服务器上传,并且符合面向对象编程的思想

JSON采用完全独立于语言的文本格式,但也使用了类似于C语言家族的习惯(包括C,C++,C#,JAVA等)

这些特性使JSON成为理想的数据交换语言,易于人阅读和编写,同时也易于机器解析和生成

可以使用NewtonJson来进行序列化。

假设有一个数据存档类,包含版本号、金币数量、体力、主武器、上下炮台、字典测试
 */
[System.Serializable]
public class Players
{
    public string name;
    public List<PlayerSaveData> playerSaveDatas = new List<PlayerSaveData>();
}
//添加可序列化标志
[System.Serializable]
public class PlayerSaveData:MonoBehaviour
{
    // 版本号 
    public string versionId;
    // 金币数量
    public int gold;
    // 体力 
    public int energy;
    // 主武器 
    public int mainWeapon;
    // 上炮台  
    public int towerUp;
    // 下炮台
    public int towerDown;

    public override string ToString()
    {
        return string.Format("gold:{0},energy:{1}",gold,energy);
    }

}

2.实体类的序列化

单个实体类的序列化包含了类的实例化、对象的序列化和数据的持久化。

类的实例化:

 PlayerSaveData data = new PlayerSaveData()
    {
        versionId = "0.01",
        gold = 1000,
        energy = 1000,
        mainWeapon = 20000,
        towerUp = 40000,
        towerDown = 40000,
    };

对象的序列化和数据的写入

 //存储Json文件
    private void SaveDatasJsonByJsonUtility()
    {
        Players players = new Players();
        players.name = "nbg";
        players.playerSaveDatas.Add(data);
        //方式2:使用JsonUtility序列化数据
        string jsonByJsonUtility=JsonUtility.ToJson(players);
        //根据文件路径,创建/打开目标文件,使用到I/O;
        StreamWriter writer = new StreamWriter(DataManager.Instance.GetPlayerDataPath());
        //将json数据写入文件中
        writer.WriteLine(jsonByJsonUtility);
        //关闭数据流
        writer.Close();
        Debug.Log("使用JsonUtility存储数据完毕");
    }

对象的反序列化和数据的读取

//读取数据并转为所需要的格式
    private void ReadDatasJson()
    {
        if (!File.Exists(DataManager.Instance.GetPlayerDataPath()))
        {
            Debug.Log("找不到存档文件");
        }
        else
        {
            Players players= new Players();
            //根据文件路径创建数据流
            StreamReader reader = new StreamReader(DataManager.Instance.GetPlayerDataPath());
            //读取json数据
            string json = reader.ReadToEnd();
            //关闭数据流
            reader.Close();
            //将获取到的Json数据转为Datas类数据,使用NewTonsoft.Json,反序列化数据
            //PlayerSaveData saveData = JsonConvert.DeserializeObject<PlayerSaveData>(json);
            Players saveData=JsonUtility.FromJson<Players>(json);
            Debug.LogFormat("name={0}", saveData.name);
            foreach (var item in saveData.playerSaveDatas)
            {

                Debug.Log(item.ToString());
            }
            
            //把读取的数据赋值给目标对象
           // Debug.LogError(saveData.versionId);
            Debug.Log("本地存档读取赋值成功");
        }
    }

3.使用JsonUtility序列化对象的Json字符串格式

注意事项: JsonUtlity无法直接读取数据集合,需要在json文件中包裹一层对象("对象名":[...])

{"name":"nbg","playerSaveDatas":[{"versionId":"0.01","gold":1000,"energy":1000,"mainWeapon":20000,"towerUp":40000,"towerDown":40000}]}

json路径管理

json路径管理代码如下:

public class DataManager : SingletonTest<DataManager>
{
    //玩家数据存档路径
    private string playerDataPath = Application.streamingAssetsPath + "/PlayerSaveDatas.json";
    public string GetPlayerDataPath()
    { 
        return playerDataPath;
    }
}

在序列化数据前,可以判断json路径下是否存在json文件。

private void OnEnable()
    {
        //if (!Directory.Exists(filePath))
        if (!File.Exists(filePath))
        {
            Debug.Log("本地没有存档");
            SaveDatasJson();//存档
        }
        ReadDatasJson();//读档
    }