Unity 数据持久化

概述

数据序列化和持久化

序列化:将对象或者数据结构转化成特定的格式,使其可在网络中传输,或者可存储在内存或者文件中。

持久化:将数据存储到可永久保存的存储介质中(如磁盘)。

序列化和反序列化

序列化:将类对象信息转换为可保存或传输的格式的过程。

反序列化:与序列化相对,将保存或传输过来的格式转换为类对象的过程。

为什么需要关注序列化?

  1.  数据持久化:保存玩家存档、配置数据、场景状态。

  2. Inspector交互:在编辑器中直观调整脚本参数。

  3. 跨平台兼容:通过标准格式(如JSON)实现不同平台间的数据交换。

  4. 性能优化:合理的序列化策略可减少内存占用和加载时间。 

PlayerPrefs

常用接口

SetInt

保存整型数据

GetInt

读取整型数据

SetFloat

保存浮点型数据

GetFloat

读取浮点型数据

SetString

保存字符串数据

GetString

读取字符串数据

DeleteAll

删除所有保存的数据(谨慎使用)

DeleteKey

删除指定键的数据

HasKey

判断本地是否有保存指定键对应的数据

Save

保存所有修改的数据

优缺点

优点

简单易用

缺点

1、只能支持三种类型的数据存取:int\float\string

2、数据安全型低

适用范围

适合用来存储暂时性数据:

1、玩家偏好设定

2、简单的数据

3、游戏原型制作时临时存储方案

Json

常用接口

JsonUtility

JsonUtility是Unity内置的JSON处理工具,不支持Dictionary、Query、Stack等集合。

1、object转json字符串

var str = JsonUtility.ToJson(obj);

 2、object转json字符串,格式化打印,看起来更直观

var str = JsonUtility.ToJson(obj);

3、json字符串转指定类型

Student result = JsonUtility.FromJson<Student>(str);

LitJSON

需要将LitJSON.dll文件放入到Plugins文件夹下,支持Dictionary

// 将数据对象转为字符串
var str = LitJson.JsonMapper.ToJson(obj);
//json字符串转为对象
Student result = LitJson.JsonMapper.ToObject<Student>(str);

提示

1、有些数据JsonUtility可以序列化而LitJSON不可以;有些数据LitJSON可以而JsonUtility不可以,所以联合使用可达奇效。

2、将获取的json字符串写入到一个文件中,并保存到Application.persistentDataPath指定的自定义文件夹下。读取的时候从该路径下就可以读取保存的数据,从而实现数据持久化。

优缺点

优点

1、方便人类阅读和编写

2、使用范围广泛,支持多种主流编程语言

3、轻量级,易于网络传输、解析和生成

缺点

1、数据安全型低

2、文件读写时效率较低

3、内存和硬盘占用空间大

适用范围

1、网络数据交换

2、存储不是很重要并且需要大量读取和修改的数据

3、玩家偏好设置

二进制

通过将各类型变量转换为字节数组,再将字节数组直接存储到文件中。

常用接口

处理非字符串数据

支持整型、浮点型、字符型、布尔型

int value = 365;
//数据转成字节数组
var array = BitConverter.GetBytes(value);
//将字节数据转成指定数据
var result = BitConverter.ToInt32(array);

处理字符串数据

var str = "好好学习,天天向上";
//字符串转byte数组
Byte[] array = Encoding.UTF8.GetBytes(str);
//byte数组转字符串
string result = Encoding.UTF8.GetString(array);

处理类对象

注意:如果要使用C#自带的序列化二进制方法,申明类时需要添加[System.Serializable]特性。如果没有这个特性,BinaryFormatter 将无法处理该类

[Serializable]
public class Student
{
    public int id;
    public string name;
    public List<int> dataList;
    public Dictionary<string, int> scoreDic;
}

第一种方法

/****************************序列化(二进制文件)****************************/
using (MemoryStream ms = new MemoryStream())
{
    //二进制格式化程序
    BinaryFormatter bf = new BinaryFormatter();

    //序列化对象 生成二进制字节数组 写入到内存流当中
    bf.Serialize(ms, obj);

    //得到对象的二进制字节数组
    byte[] bytes = ms.GetBuffer();

    //存储字节
    File.WriteAllBytes(Application.dataPath + "/Test.bytes", bytes);
}

/****************************反序列化(二进制文件)****************************/
//目前没有网络传输 我们还是直接从文件中获取
byte[] bytes = File.ReadAllBytes(Application.dataPath + "/Test.bytes");
//申明内存流对象 一开始就把字节数组传输进去
using (MemoryStream ms = new MemoryStream(bytes))
{
    //申明一个 2进制格式化程序
    BinaryFormatter bf = new BinaryFormatter();
    //反序列化
    var result = bf.Deserialize(ms) as Student;
}

第二种方法

var filePath = Application.dataPath + "/Student.bytes";
/****************************序列化(二进制文件)****************************/
using (FileStream fs = File.OpenWrite(filePath)){
    //申明一个二进制格式化类
    BinaryFormatter bf = new BinaryFormatter();
    //序列化对象 生成2进制字节数组 写入到内存流当中
    bf.Serialize(fs, obj);
}

/****************************反序列化(二进制文件)****************************/
//通过文件夹流打开指定的2进制数据文件
using (FileStream fs = File.OpenRead(filePath)){
    //申明一个二进制格式化类
    BinaryFormatter bf = new BinaryFormatter();
    //反序列化
    Student result = bf.Deserialize(fs) as Student;
}

优缺点

优点

(相比于json和xml方案)

1、安全性较高

2、文件读写时效率较高

3、内存和硬盘占用空间小

缺点

1、可读性低,不易于人类阅读

适用范围

广泛应用于网络通信

XML(不推荐)

不支持序列化字典

//XML序列化
void SerializeToXML<T>(T data, string path) {
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (StreamWriter stream = new StreamWriter(path)) {
        serializer.Serialize(stream, data);
    }
}

//XML反序列化
T DeserializeFromXML<T>(string path) {
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (StreamReader stream = new StreamReader(path)) {
        return (T)serializer.Deserialize(stream);
    }
}