序列化
序列化是指把对象转换为字节序列的过程,而反序列化是指将字节序列恢复为对象的过程。
序列化最主要的用途就是传递对象和保存对象。
在Unity中保存和加载、prefab、Scene、Inspector窗口、实例化预制体等都使用了序列化和反序列化。下面是一个序列化和反序列化的例子。
[Serializable]
public class Player
{
public int coin = 0;
public int money = 0;
public string name = "";
}
Player player = new Player();
player.coin = 1;
player.money = 10;
player.name = "XiaoMing";
//序列化
using (Stream stream = new FileStream("data.bin", FileMode.Create, FileAccess.Write, FileShare.None)) {
IFormatter formatter = new BinaryFormatter();
//序列化对象 生成2进制字节数组 写入到内存流当中
formatter.Serialize(stream, player);
stream.Close();
}
//反序列化
using (Stream stream2 = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read))
{
Console.WriteLine(stream2.ToString());
IFormatter formatter2 = new BinaryFormatter();
Player player2 =(Player)formatter2.Deserialize(stream2);
Console.WriteLine(player2.coin);
Console.WriteLine(player2.money);
Console.WriteLine(player2.name);
stream2.Close();
}
补充:使用using更安全的使用文件流对象
using关键字重要用法
using (申明一个引用对象)
{
使用对象
}
无论发生什么情况,当using语句块结束后,会自动调用该对象的销毁方法,避免忘记销毁或关闭流。using是一种更安全的使用方法。目前我们对文件流进行操作,为了文件操作安全,都用using来进行处理最好。
二进制
二进制文件的读写本质,就是通过将各类型变量转换为字节数组,将字节数组直接存储到文件中,一般人是看不懂存储的数据的,不仅可以节约存储空间,提升效率,还可以提升安全性,而且在网络通信中我们直接传输的数据也是字节数据(二进制数据)。
二进制持久化的一个主要应用就是序列化和反序列化。这里再补充一些常用用法。
- 变量的本质是2进制,在内存中都以字节的形式存储着,通过sizeof方法可以看到常用变量类型占用的字节空间长度
sizeof(int)
- C#提供了一个公共类BitConverter可以将各类型数据和字节数据相互转换
- 将各类型转字节
byte[] bytes = BitConverter.GetBytes(256);
- 字节数组转各类型
int i = BitConverter.ToInt32(bytes, 0);
- C#中有一个专门的编码格式类Encoding可以将字符串和字节数组进行转换
- 将字符串以指定编码格式转字节
byte[] bytes2 = Encoding.UTF8.GetBytes("abc");
- 字节数组以指定编码格式转字符串
string s = Encoding.UTF8.GetString(bytes2);
Json
1. JsonUtility
JsonUtility是Unity自带的用于解析Json的工具类。它可以将内存中对象序列化为Json格式的字符串,将Json字符串反序列化为类对象。
用法:
//将对象序列化为Json格式的字符串
public string ToJson()
{
return JsonUtility.ToJson(this);
}
//将Json字符串转化为类对象
public GameData FromJson(string json)
{
return JsonUtility.FromJson<GameData>(json);
}
注意:
- float序列化时看起来会有一些误差
- 自定义类需要加上序列化特性[System.Serializable]
- 想要序列化私有变量 需要加上特性[SerializeField]
- JsonUtility不支持字典
- JsonUtility不能直接将数据反序列化为数据集合
- JsonUtility存储null对象不会是null 而是默认值的数据
- Json文档编码格式必须是UTF-8
2. LitJson
LitJson是一个第三方库,用于处理Json的序列化和反序列化。
用法:
//将对象序列化为Json格式的字符串
public string ToJson()
{
return JsonMapper.ToJson(this);
}
//将Json字符串转化为类对象
public GameData ToObject(string json)
{
return JsonMapper.ToObject<GameData>(json);
}
注意:
- LitJson无需加特性
- LitJson不支持私有变量
- LitJson支持字典序列化反序列化
- LitJson可以直接将数据反序列化为数据集合
- LitJson反序列化时 自定义类型需要无参构造
- LitJson可以准确的保存null类型
- Json文档编码格式必须是UTF-8
PlayerPrefs
PlayerPrefs是Unity用于存储和读取玩家数据的一个公共类。
PlayerPrefs的数据存储类似于键值对存储,一个键对应一个值,并且它的key是唯一的。它提供了存储3种数据的方法 int float string
键: string类型
值:int float string 对应3种API
存储相关
PlayerPrefs.SetInt("myAge", 22);
PlayerPrefs.SetFloat("myHeight", 172.5f);
PlayerPrefs.SetString("myName", "abc");
直接调用Set相关方法只会把数据存到内存里,当游戏结束时,Unity会自动把数据存到硬盘中。如果游戏不是正常结束的,而是崩溃,数据是不会存到硬盘中的。所以只要调用PlayerPrefs.Save();
,数据就会马上存储到硬盘中。
读取相关
int age = PlayerPrefs.GetInt("myAge");
float height = PlayerPrefs.GetFloat("myHeight");
string name = PlayerPrefs.GetString("myName");
//如果找不到myAge对应的值 就会返回函数的第二个参数 默认值,其他两个API也是如此
age = PlayerPrefs.GetInt("myAge", 100);
//判断数据是否存在
PlayerPrefs.HasKey("myName");
删除相关
//删除指定键值对
PlayerPrefs.DeleteKey("myAge");
//删除所有存储的信息
PlayerPrefs.DeleteAll();
PlayerPrefs在不同平台存储的位置是不一样的。
Windows平台是存储在注册表中,位置是HKCU\Software\公司名称\产品名称
,其中公司和产品名称是在“Project Settings”中设置的名称。
Android平台是存储在/data/data/包名/shared_prefs/pkg-name.xml
。
IOS平台是存储在/Library/Preferences/com.公司名.项目名.plist
。