存储数据:使用JsonUtility.ToJson(this)将当前类的公有成员变量转为json,并存储到json文件
读取数据:从json文件中读取数据,并通过Type.GetFields来给所有数据赋值
优点:对于简单的数据类型,不用自己将需存储的数据一个一个的存储到文件中,也不用自己解析读取的数据。
复杂数据:
list:用string来表示,读取的时候再解析string为list,每次修改重新将list数据解析回字符串。
dictionary字典:用string来表示,读取的时候再解析dictionary为list,每次修改重新将dictionary数据解析回字符串。
数据泛型类
利用C# 反射 - FieldInfo来进行读取存档后的,数据对象的变量赋值。
using UnityEngine;
using System.IO;
using System;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
[Serializable]
public class LocalDataBase<T> where T : LocalDataBase<T>
{
public string name;
private static string savePath = Init();
private static string Init()
{
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
savePath = Path.Combine(Application.persistentDataPath, "GameRes");
}
else
{
savePath = Application.dataPath.Replace("/Assets", "/SaveRes");
}
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
return savePath;
}
public LocalDataBase()
{
name = typeof(T).Name;
}
/// 保存至配置
public virtual void Save()
{
string path = Path.Combine(savePath, name + ".json");
FileInfo file = new FileInfo(path);
if (file.Exists)
{
file.Delete();
}
try
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(this));
Stream stream = file.Create();
stream.Write(bytes, 0, bytes.Length);
stream.Close();
stream.Dispose();
}
catch (System.Exception e)
{
Debug.Log(e.Message);
}
}
/// 加载配置
public virtual void Load()
{
string path = Path.Combine(savePath, name + ".json");
FileInfo file = new FileInfo(path);
if (file.Exists)
{
Stream stream = file.Open(FileMode.Open);
stream.Position = 0;
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
stream.Close();
stream.Dispose();
if (string.IsNullOrEmpty(text.Trim()))
{
text = "{}";
}
T obj = JsonUtility.FromJson<T>(text);
Type DataType = typeof(T);
FieldInfo[] fields = DataType.GetFields(); // 返回当前 Type 的所有公共字段
for (int i = 0; i < fields.Length; i++)
{
fields[i].SetValue(this, fields[i].GetValue(obj)); // 设置当前 Type 的所有公共字段的值
}
}
else
{
Save(); // 若无存档,则将当前初始化的数据保存为存档
}
}
}
实例类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerData : LocalDataBase<PlayerData>
{
#region 单例
private static PlayerData instance = null;
private static System.Object mObject = new object();
public static PlayerData Instance
{
get
{
lock (mObject)
{
if (instance == null)
{
instance = new PlayerData();
instance.Init();
}
return instance;
}
}
}
#endregion
#region 数据
public string str;
public int i;
public bool b;
public Vector3 V3;
public List<int> pStarList = null;//星星列表
public List<string> pListRole = null;//角色解锁列表
#endregion
private void Init()
{
str = "abc";
i = 5;
b = true;
V3 = new Vector3(4, 5, 6);
InitStarList();
InitListRole();
}
#region 列表初始化
private void InitStarList()
{
pStarList = new List<int>();
for (int i = 0; i < 20; i++)
{
pStarList.Add(0);
}
}
private void InitListRole()
{
pListRole = new List<string>();
for (int i = 1; i <= 5; i++)
{
string temp = i + "101";
string content = string.Empty;
content = temp + "|" + 0;
pListRole.Add(content);
}
}
#endregion
public override void Save()
{
base.Save();
}
public override void Load()
{
base.Load();
}
}
测试类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System;
public class Test : MonoBehaviour {
void Start () {
PlayerData.Instance.Load(); // 相当于先初始化数据,再加载存档,若存在存档则覆盖初始化的数据
// 打印字段名称
Type DataType = typeof(PlayerData);
FieldInfo[] fieldInfo = DataType.GetFields();
for (int i = 0; i < fieldInfo.Length; i++)
{
print("字段名称:" + fieldInfo[i]);
}
// 打印加载后的列表数据,修改了几个存档参数测试
for (int i = 0; i < PlayerData.Instance.pListRole.Count; i++)
{
print("角色:" + PlayerData.Instance.pListRole[i]);
}
}
}
测试日志:
Type.GetFields
返回当前 Type 的所有公共字段。
注意要引用命名空间:using System.Reflection;
json文件的内容:
{"name":"PlayerData","str":"abc","i":5,"b":true,"V3":{"x":4.0,"y":5.0,"z":6.0},"pStarList":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"pListRole":["1101|1","2101|0","3101|0","4101|0","5101|1"]}
JsonUtility的缺点:
1、无法直接序列化和反序列化Dictionary<TKey,TValue> ,也就是说,使用Dictionary则需要二次转换才行。
List和Dictionary的通用读取与修改
list:用string来表示,读取的时候再解析string为list,每次修改重新将list数据解析回字符串。
dictionary字典:用string来表示,读取的时候再解析dictionary为list,每次修改重新将dictionary数据解析回字符串。
1、初始化
public PlayerData()
{
pHeadIconUnlock = "1|0|0|0"; // 头像ID 1解锁未使用 0锁着
pNaturalGiftID_LigthUpState= "1001|0|0|0|0|0,1002|0|0|0|0|0,1003|0|0|0|0|0,1004|0|0|0|0|0"; //每个list用逗号分隔,list里面的每个参数用竖分隔,每个list的第一个值为字典的key
}
2、读取与修改
// list
// 头像icon解锁
public string pHeadIconUnlock;
private List<int> m_lstHeadIconUnlock;
public List<int> GetHeadIconUnlock()
{
m_lstHeadIconUnlock = GetLstData(m_lstHeadIconUnlock, pHeadIconUnlock);
return m_lstHeadIconUnlock;
}
public void SetHeadIconUnlock(int _id, int _value)
{
pHeadIconUnlock = SetLstData(m_lstHeadIconUnlock, _id, _value);
}
// dictionary
public string pNaturalGiftID_LigthUpState; // 点亮的天赋ID
// 获取角色点亮天赋的数组
private Dictionary<int, List<int>> m_LightUpNaturalGiftID;
/// <summary>
/// 获取天赋点亮的ID,字典的int为角色ID,list的int为天赋级别
/// </summary>
/// <returns></returns>
public Dictionary<int, List<int>> GetLightUpNaturalGiftID()
{
m_LightUpNaturalGiftID = GetDicData(m_LightUpNaturalGiftID, pNaturalGiftID_LigthUpState);
return m_LightUpNaturalGiftID;
}
/// <summary>
/// 点亮角色天赋
/// </summary>
/// <param name="roleId">角色ID</param>
/// <param name="id_NG">天赋ID</param>
public void LightUpNatuarlGiftId(int roleId, int id_NG)
{
if (roleId == m_LightUpNaturalGiftID[roleId][0])
{
int level = NaturalGiftData.DicData[id_NG].Level;
pNaturalGiftID_LigthUpState = SetDicData(m_LightUpNaturalGiftID, roleId, level, id_NG);
}
}
3、通用的读取与修改
/// <summary>
/// 获取list数据
/// </summary>
/// <param name="_lstData"></param>
/// <param name="_strData">字符串数据</param>
/// <returns></returns>
private List<int> GetLstData(List<int> _lstData, string _strData)
{
if (_lstData == null)
{
_lstData = new List<int>();
string[] strValue = _strData.Split('|');
for (int i = 0; i < strValue.Length; i++)
{ _lstData.Add(int.Parse(strValue[i])); }
}
return _lstData;
}
/// <summary>
/// 修改list数据
/// </summary>
/// <param name="_lstData">要修改的list数据</param>
/// <param name="_id">键值</param>
/// <param name="_value">新的值</param>
/// <returns></returns>
private string SetLstData(List<int> _lstData, int _id, int _value)
{
_lstData[_id] = _value;
string strValue = "";
for (int i = 0; i < _lstData.Count; i++)
{
if (i == _lstData.Count - 1)
strValue += _lstData[i];
else
strValue += _lstData[i] + "|"; // list中的分隔符
}
return strValue;
}
/// <summary>
/// 获取dictionary数据
/// </summary>
/// <param name="dicData">字典集合</param>
/// <param name="strData">字符串数据</param>
/// <returns></returns>
private Dictionary<int, List<int>> GetDicData(Dictionary<int, List<int>> dicData, string strData)
{
if(dicData == null)
{
dicData = new Dictionary<int, List<int>>();
string[] strValue = strData.Split(',');// 字典中的list分隔符
for (int i = 0; i < strValue.Length; i++)
{
int io = strValue[i].IndexOf('|');
int key = int.Parse(strValue[i].Substring(0, io)); // 获取字典的键值
dicData[key] = null;
dicData[key] = GetLstData(dicData[key], strValue[i]);
}
}
return dicData;
}
//"1001|0|0|0|0|0,1002|0|0|0|0|0"
/// <summary>
/// 修改字典的数据
/// 如"1001|0|0|0|0|0,1002|0|0|0|0|0"
/// 每个list用逗号分隔,list里面的每个参数用竖分隔,每个list的第一个值为字典的key
/// </summary>
/// <param name="dicData">要修改的字典</param>
/// <param name="key">字典的键值</param>
/// <param name="id">list的键值</param>
/// <param name="value">list的值</param>
/// <returns></returns>
private string SetDicData(Dictionary<int,List<int>> dicData, int key, int id, int value)
{
dicData[key][id] = value;
string strValue = "";
foreach (int tempkey in dicData.Keys)
{
strValue += SetLstData(dicData[tempkey], 0, dicData[tempkey][0]) + ",";// 字典中的list分隔符
}
strValue = strValue.Substring(0, strValue.Length - 1);
return strValue;
}