Unity存档之json(使用JsonUtility与Type.GetFields)

存储数据:使用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;
    }

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值