序列化: 将数据结构或对象转换成二进制串的过程。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
首先我们通过复制文件举例,这里面就包含序列化与反序列化的过程:
public class Test2 : MonoBehaviour { byte[] buffer; private void Start() { //一次性复制 适用于比较小的文件,如文本文档等。 //序列化过程 using (FileStream stream = new FileStream(Application.dataPath + @"Resources123.txt", FileMode.Open, FileAccess.Read)) { //创建一个 byte 类型数组,用来存储通过文件流读取的文件,数组的长度就是文件的长度。 buffer = new byte[stream.Length]; //将读取到的文件转为字节数组存入 buffer 数组中 stream.Read(buffer, 0, buffer.Length); } //反序列化过程 using (FileStream stream = new FileStream(Application.dataPath + @"Floder1123.txt", FileMode.Create, FileAccess.Write)) { //将 buffer 数组中的字节转换回相应的格式,并写入相应文件中 stream.Write(buffer, 0, buffer.Length); } } }
public class Test2 : MonoBehaviour { byte[] buffer;//声明一个字节数组 private void Start() { //分批量复制 适用于比较大的文件,如音频、视频等文件。 //定义每次读入的文件大小,10KB。 int maxSize = 10240; //开启读入流 FileStream streamRead = new FileStream(Application.dataPath + @"Resources吴奇隆 - 转弯.mp3", FileMode.Open, FileAccess.Read); //开启写入流 FileStream streamWrite = new FileStream(Application.dataPath + @"Floder1转弯.mp3", FileMode.Create, FileAccess.Write); //实例化数组,长度为 maxSize。 buffer = new byte[maxSize]; //当前读取的字节数量 int num = 0; do { //读入文件 num = streamRead.Read(buffer, 0, maxSize); //写入文件 streamWrite.Write(buffer, 0, num); } while (num > 0); //释放流 streamWrite.Dispose(); streamRead.Dispose(); } }
下面这个例子是做了一个 Cube 的预制体,然后场景中放一个预制体,通过存档将 Cube 的信息序列化存入硬盘中,通过读档再将 Cube 的信息反序列化出来,生成在场景中,一般用于游戏存档功能。
Unity3D中大部分类(例如:Vector3)是不能被序列化的,所以这个时候我们需要使用 IFormatter 类,并自己写出一些可以序列化的类(例如下面代码中的:Info 和 VectorX 这个两个类就是我自己写的可以用来序列化的类)来替代这些类,从而实现序列化。这里写这个只是想让大家明白序列化的原理。一般来说,我们都会使用 JsonUtility 类来实现游戏的存档功能,非常简单,在下面的代码方法二中有举例。我们也可以使用 LitJson 插件来实现,用法与 JsonUtility 大同小异,网上有很多教程,这里就不多说了。
1 using UnityEngine; 2 using System.IO; 3 using System.Runtime.Serialization.Formatters.Binary; 4 using System.Runtime.Serialization; 5 using System; 6 7 public class Test1 : MonoBehaviour { 8 public GameObject cube; 9 void OnGUI() 10 { 11 if (GUILayout.Button("存档")) 12 { 13 cube = GameObject.Find("Cube"); 14 if (cube != null) 15 { 16 Color c = cube.GetComponent<MeshRenderer>().material.color; 17 Info info = new Info(cube.transform.position, c.r, c.g, c.b, c.a); 18 //方法一: 19 IFormatter formatter = new BinaryFormatter(); 20 Stream stream = new FileStream(Application.dataPath + "/info.obj", FileMode.Create, FileAccess.Write); 21 formatter.Serialize(stream, info); 22 stream.Close(); 23 24 //方法二: 25 //string str = JsonUtility.ToJson(info); 26 //File.WriteAllText(Application.dataPath + "/info.txt", str); 27 } 28 else 29 { 30 throw new Exception("物体不存在!"); 31 } 32 } 33 if (GUILayout.Button("读档")) 34 { 35 GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); 36 IFormatter formatter = new BinaryFormatter(); 37 //方法一: 38 Stream stream = new FileStream(Application.dataPath + "/info.obj", FileMode.Open, FileAccess.Read); 39 Info info = (Info)formatter.Deserialize(stream); 40 go.transform.position = info.pos; 41 go.GetComponent<MeshRenderer>().material.color = new Color(info.r, info.g, info.b, info.a); 42 stream.Dispose(); 43 44 //方法二: 45 //string str = File.ReadAllText(Application.dataPath + "/info.txt"); 46 //Info info = JsonUtility.FromJson<Info>(str); 47 //go.transform.position = info.pos; 48 //go.GetComponent<MeshRenderer>().material.color = new Color(info.r, info.g, info.b, info.a); 49 } 50 } 51 } 52 //在类的上面加上这个标签,这个类才能被序列化,需要注意。 53 [System.Serializable] 54 public class Info 55 { 56 public VectorX pos; 57 public float r; 58 public float g; 59 public float b; 60 public float a; 61 62 public Info(VectorX pos,float r,float g,float b,float a) 63 { 64 this.pos = pos; 65 this.r = r; 66 this.g = g; 67 this.b = b; 68 this.a = a; 69 } 70 }