数据持久化
- 将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型
- 是一种存盘操作
what(Json是什么?)
- Json是Javascript的对象简谱
- 一种轻量化的数据交换格式
- 用于传输数据,本地存储和读取数据
why(为什么使用Json)
- json配置简单
- json读写更为快速
how(怎么使用Json)
Unity中使用JsonUtlity,关于JsonUtility,描述如下:
- Unity自带的用于解析Json的公共类
- 可以将内存中的对象序列化为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, 该路径包含持久数据目录的路径(只读),- 该值是目录路径;此目录中可以存储每次运行要保留的数据。在 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();//读档
}