Unity数据持久化-Json

文章目录

    • JSON概念:
    • JSON结构:
    • JSON优势:
    • 与JavaScript的关系:
    • Unity方法:
    • 使用JsonUtility
      • Json存储
      • Json加载:
      • 注意事项:
    • 完整代码参考:
    • 使用LitJson:
      • 存储方法:
      • 读取方法
      • 注意事项

JSON概念:

JSON(JavaScript Object Notation)一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式,同时也具备类似于C语言的习惯体系的行为。这些特性使JSON成为理想的数据交换语言。

JSON结构:

JSON语法是javaScript语法的子集,javaScript用【】中括号来表示数组,用{}大括号来表示对象,JSON亦是如此。

JSON优势:

解析速度快,数据格式比较简单,易于读写,格式都是压缩的,占用带宽小。支持多种语言,便于服务器端的解析。因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。

与JavaScript的关系:

JavaScript为编程语言,Json是数据格式/语法。JSON独立于语言而存在,任何站在语言的角度及对象层面对他的解释都是有局限性或者是错误的。

Unity方法:

Unity 5.3之后自带了JsonUtility类处理Json数据 ,JsonUtility比其他Json库更快,常用的还有.Net库的Json.Net与LitJson, JsonUtility很快且GC很少。

FileStream vs StreamWriter vs StreamReader:

由于FileStream类读取的是字节数组,也就导致了它适合读取的是二进制文件 。

我们对文本的读写一般使用StreamReader和StreamWriter,因为不同的文本有不同的编码格式,这个StreamReader和和StreamWriter会帮我们自动处理,不需要关心文本文件的编码是什么。

使用JsonUtility

JsonUtility对List和Dictionary的序列化,List被类封装后可以序列化,Dictionary是将Key和Value分开存到两个List进行的序列化
https://blog.csdn.net/truck_truck/article/details/78292390
使用步骤:

Json存储

1先创建一个文件,2然后将数据转为Json字符串,3将字符串写入文件,4关闭文件

public void SaveByJosn()
    {
        StreamWriter streamWriter = new StreamWriter("C:/Users/17641/Desktop" + "/date.txt");//放在桌面便于观察,建议放在Application.dataPath
        StreamWriter streamWriter2 = new StreamWriter("C:/Users/17641/Desktop" + "/dateDic.txt");//存放字典的文件,与普通数据分开存放,带字典的数据和普通数据存一起会解析失败
        Save save = initDate();//初始化数据

        string JsonString = JsonUtility.ToJson(save);//存储普通数据 int float string List(里面不能放字典)
        streamWriter.Write(JsonString);

        string JsonDic = JsonUtility.ToJson(new Serialization<string, int>(save.h));//存储字典
        streamWriter2.Write(JsonDic);

        //foreach (var item in save.c)
        //{
        //    string JsonListDic = JsonUtility.ToJson(new Serialization(item));//存储列表(里面放字典),无法读取,可以存
        //    streamWriter2.Write(JsonListDic);
        //}

        streamWriter.Close();
        streamWriter2.Close();
    }

字典的存放:写一个泛型类,将字典拆的Key和Value拆分成两个List进行存放

/// 
/// 对字典的序列化,使用list进行存储字典的数据
/// 
/// 
/// 
[Serializable]
public class Serialization<TKey, TValue> : ISerializationCallbackReceiver
{
    [SerializeField]
    List<TKey> keys;//存放Key的列表
    [SerializeField]
    List<TValue> values;//存放Value的列表

    Dictionary<TKey, TValue> target;//目标字典
    public Dictionary<TKey, TValue> ToDictionary() { return target; }

    public Serialization(Dictionary<TKey, TValue> target)
    {
        this.target = target;
    }

    public void OnBeforeSerialize() //序列化之前进行List拆分
    {
        keys = new List<TKey>(target.Keys);
        values = new List<TValue>(target.Values);
    }

    public void OnAfterDeserialize()//反序列化之后进行字典的组合
    {
        var count = Math.Min(keys.Count, values.Count);
        target = new Dictionary<TKey, TValue>(count);
        for (var i = 0; i < count; ++i)
        {
            target.Add(keys[i], values[i]);
        }
    }
}

Json加载:

    /// 
    /// 需要一个对应的结构体来接收,此处为Save
    /// 
    public void LoadByJson()
    {
        Save save = new Save();
        if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
        {
            StreamReader reader = new StreamReader("C:/Users/17641/Desktop" + "/date.txt");
            string JsonString = reader.ReadToEnd();
            reader.Close();//从文件得到字符串后关闭文件

            save = JsonUtility.FromJson<Save>(JsonString);//对字符串进行拆分赋值,反序列化,读取非字典的数据
           

            StreamReader reader2 = new StreamReader("C:/Users/17641/Desktop" + "/dateDic.txt");
            string JsonString2 = reader2.ReadToEnd();
            reader2.Close();
            //save.c.Add(JsonUtility.FromJson>(JsonString2).ToDictionary());//读取带字典的列表,读取失败
            save.h = JsonUtility.FromJson<Serialization<string, int>>(JsonString2).ToDictionary();//读取字典的数据,Save类含有字典和非字典的数据,所以分开存放,分开读取


        }
        else
        {
            Debug.Log("No File");
            return;
        }

        Debug.Log(save.a);
        Debug.Log(save.b);
        //Debug.Log(save.c[0][0]);//对列表里面装字典,无法读取
        //Debug.Log(save.c[0][1]);
        //Debug.Log(save.c[1][2]);

        Debug.Log(save.g[3]);//列表
        Debug.Log(save.h["Attack10"]);//字典
    }
}

注意事项:

如果字典和普通数据(int float string List)放在一起存,Json会解析失败:
在这里插入图片描述

用校验工具试一下:
Unity数据持久化-Json_第1张图片

分开存放,可以读取成功
在这里插入图片描述

如果用字典装列表,再存放,会解析失败,所以装载字典的Json文件要纯粹,不能用列表包起来(数组没试过)
Unity数据持久化-Json_第2张图片

完整代码参考:

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

//需要序列化存储的类型Save,内含字典和非字典的数据
[SerializeField]
public class Save : ISerializationCallbackReceiver
{
    public int a;
    public string b;

    public List<Dictionary<int, string>> c = new List<Dictionary<int, string>>();
    public float f;

    public List<string> Tkey;
    public List<float> Tvalue;

    public List<string> g = new List<string>();

    public Dictionary<string, int> h = new Dictionary<string, int>();

    public void OnAfterDeserialize()
    {
        Debug.Log("反序列化");
    }

    public void OnBeforeSerialize()
    {
        Debug.Log("开始系列化");
    }
}


/// 
/// 对字典的序列化,使用list进行存储字典的数据
/// 
/// 
/// 
[Serializable]
public class Serialization<TKey, TValue> : ISerializationCallbackReceiver
{
    [SerializeField]
    List<TKey> keys;
    [SerializeField]
    List<TValue> values;

    Dictionary<TKey, TValue> target;
    public Dictionary<TKey, TValue> ToDictionary() { return target; }

    public Serialization(Dictionary<TKey, TValue> target)
    {
        this.target = target;
    }

    public void OnBeforeSerialize()
    {
        keys = new List<TKey>(target.Keys);
        values = new List<TValue>(target.Values);
    }

    public void OnAfterDeserialize()
    {
        var count = Math.Min(keys.Count, values.Count);
        target = new Dictionary<TKey, TValue>(count);
        for (var i = 0; i < count; ++i)
        {
            target.Add(keys[i], values[i]);
        }
    }
}
//要在Unity中使用,在Star方法中调用一次
public class JsonTest : MonoBehaviour
{
    public static Dictionary<int, string> d = new Dictionary<int, string>();
    public static Dictionary<int, string> e = new Dictionary<int, string>();
    public static List<string> L = new List<string>();

    private void Start()
    {
        if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
        {
            Debug.Log("There are files!");
        }
        else
        {
            Debug.Log("No File");
        }
        SaveByJosn();
        LoadByJson();

        if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
        {
            Debug.Log("Save Sucess!");
        }
        else
        {
            Debug.Log("No File");
        }
    }
    //初始化数据
    public static Save initDate()
    {
        Save save = new Save();
        save.a = 18;
        save.b = "Hello Save";
        save.f = 0.98765f;

        d.Add(0, "这是一个键值为0的字典的内容");
        d.Add(1, "This is the contents of a dictionary with a key value of 1");
        e.Add(2, "@#$%^&*()");
        save.c.Add(d);
        save.c.Add(e);//列表带字典,存了两个字典(d,e)的列表

        L.Add("gggggggggg");//列表
        L.Add("asdasd");
        L.Add("098765432");
        L.Add("*&^^%%$%");
        save.g = L;

        save.h.Add("Attack1", 123);//字典
        save.h.Add("Attack2", 1234);
        save.h.Add("Attack3", 1232);
        save.h.Add("Attack4", 1223);
        save.h.Add("Attack10", 1233);
        save.h.Add("Attack15", 1243);

        return save;
    }

    public void SaveByJosn()
    {
        StreamWriter streamWriter = new StreamWriter("C:/Users/17641/Desktop" + "/date.txt");//放在桌面便于观察,建议放在Application.dataPath
        StreamWriter streamWriter2 = new StreamWriter("C:/Users/17641/Desktop" + "/dateDic.txt");//存放字典,分开存放,带字典的数据和普通数据存一起会解析失败
        Save save = initDate();//初始化数据

        string JsonString = JsonUtility.ToJson(save);//存储普通数据 int float string List(里面不能放字典)
        streamWriter.Write(JsonString);

        string JsonDic = JsonUtility.ToJson(new Serialization<string, int>(save.h));//存储字典
        streamWriter2.Write(JsonDic);

        //foreach (var item in save.c)
        //{
        //    string JsonListDic = JsonUtility.ToJson(new Serialization(item));//存储列表(里面放字典)
        //    streamWriter2.Write(JsonListDic);
        //}

        streamWriter.Close();
        streamWriter2.Close();
    }

    /// 
    /// 需要一个对应的结构体来接收,此处为Save
    /// 
    public void LoadByJson()
    {
        Save save = new Save();
        if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
        {
            StreamReader reader = new StreamReader("C:/Users/17641/Desktop" + "/date.txt");
            string JsonString = reader.ReadToEnd();
            reader.Close();//从文件得到字符串

            save = JsonUtility.FromJson<Save>(JsonString);//对字符串进行拆分赋值,反序列化,读取非字典的数据
           

            StreamReader reader2 = new StreamReader("C:/Users/17641/Desktop" + "/dateDic.txt");
            string JsonString2 = reader2.ReadToEnd();
            //save.c.Add(JsonUtility.FromJson>(JsonString2).ToDictionary());//读取带字典的列表
            save.h = JsonUtility.FromJson<Serialization<string, int>>(JsonString2).ToDictionary();//读取字典


        }
        else
        {
            Debug.Log("No File");
            return;
        }

        Debug.Log(save.a);
        Debug.Log(save.b);
        //Debug.Log(save.c[0][0]);//对列表里面装字典
        //Debug.Log(save.c[0][1]);
        //Debug.Log(save.c[1][2]);

        Debug.Log(save.g[3]);//列表
        Debug.Log(save.h["Attack10"]);//字典
    }
}

使用LitJson:

存储方法:

1.建立存储类型,
2.对存储类型进行赋值,
3.使用string JsonStr = JsonMapper.ToJson(LitData);转成Json字符串,
4.使用File.WriteAllText(“C:/Users/17641/Desktop” + “/dateLit.txt”, JsonStr); 存储

例:

public class LitJsonData
{
    public int intLit;
    public string strLit;

    public List<string> ListLit= new List<string>();

    public Dictionary<string, int> DicList = new Dictionary<string, int>();

    public List<Dictionary<int, string>> ListDicLit = new List<Dictionary<int, string>>();
}
public void LitJsonSave()
    {
        //初始化数据
        LitJsonData LitData = new LitJsonData();
        LitData.intLit = 15;
        LitData.strLit = "这是一个用LitJson存储的字符串";

        L.Add("!@#!$$");
        L.Add("这是List的数据");
        LitData.ListLit = L;

        //LitData.DicList.Add("字典内容1", 15);带字典的内容可以存储成功,但是读取会失败

        //LitData.DicList.Add("字典内容2", 18);

        //d.Add(15, "List+Dic1");
        //d.Add(18, "List+Dic12");

        //e.Add(10, "List+Dic2");

        //LitData.ListDicLit.Add(d);
        //LitData.ListDicLit.Add(e);
        //初始化完毕

        //序列化
        string JsonStr = JsonMapper.ToJson(LitData);//LitJson不需要标记【SerializeField】
        //Debug.Log(JsonStr);
        File.WriteAllText("C:/Users/17641/Desktop" + "/dateLit.txt", JsonStr);//存到文件中,如果不存在会自动创建
        if (File.Exists("C:/Users/17641/Desktop" + "/dateDic.txt"))
        {
            Debug.Log("JsonLit Save Sucess!");
        }
    }

Unity数据持久化-Json_第3张图片
可以看到保存成文件后,中文被转码

读取方法

得到Json字符串,使用JsonMapper.ToObject进行反序列化,并赋予结构体,之后即可使用

public void LitJsonLoad()
    {
        string JsonLitLoad = File.ReadAllText("C:/Users/17641/Desktop" + "/dateLit.txt");//可以使用try进行安全校验,读取Json字符串

        //用结构体接收 LitJsonData
        LitJsonData LitDataLoad = new LitJsonData();

        LitDataLoad = JsonMapper.ToObject<LitJsonData>(JsonLitLoad);

        Debug.Log(LitDataLoad.strLit);//字符串
        Debug.Log(LitDataLoad.intLit);//整数
        Debug.Log(LitDataLoad.ListLit[0]);//列表 一号元素对应的内容  L.Add("!@#!$$");

        //Debug.Log(LitDataLoad.DicList["字典内容1"]);//字典,key为字典内容1对应的内容,带字典的内容可以存储成功,但是读取会失败

        //Debug.Log(LitDataLoad.ListDicLit[0][18]);//对应第一个字典,Key为18的内容,即  d.Add(18, "List+Dic12");
    }

Unity数据持久化-Json_第4张图片
**

注意事项

**:字典可以存储,但是无法读取,要对数据进行类似JsonUtility的改造

带字典的存储
Unity数据持久化-Json_第5张图片
带字典的读取:
Unity数据持久化-Json_第6张图片
读取失败

你可能感兴趣的:(unity基础,json,Unity,unity3d)