Unity 二进制读写小框架
文章目录
- 前言
- 框架获取与集成
- 使用方法
- 基本配置
- 自动生成序列化方法
- 实战示例
- 技术原理与优势
- 二进制序列化的优势
- SJBinary的设计特点
- 最佳实践建议
- 适用场景
- 总结
前言
在Unity开发过程中,与后台交互时经常需要处理大型数据文件。当遇到一个近2MB的本地JSON文件需要解析为对象时,使用传统的JSON解析方案(无论是Unity自带的JsonUtility还是流行的Newtonsoft Json.NET)都面临着显著的性能瓶颈。在实测中,这些方案解析时间可能长达3秒以上,即使经过优化也需要约1.5秒,同时还伴随着大量的GC(垃圾回收)开销。
针对这一问题,我们开发了一个高性能的二进制序列化框架——SJBinary。经过测试,该框架在性能表现上超越了市面上多数JSON框架和Unity自带的BinaryFormatter,接近Protobuf-net的性能水平,虽然略低于MessagePack,但其集成简单、代码量小的特点使其成为Unity项目中数据序列化的优秀选择。
实测数据显示,使用SJBinary创建10万个对象并序列化为二进制数据仅需480多毫秒,反序列化过程仅需340多毫秒,性能提升显著。
提示:二进制数据处理本质上比JSON处理更加高效,因为它避免了文本解析的复杂过程,直接使用二进制格式表示数据。
框架获取与集成
sjgenerate下载链接
1.点击上面链接即可下载
2.下载完后将SjBinary拖入项目即可
3.定义类并添加注解[SJBinary]及实现接口ISJSerializable
使用方法
基本配置
[SJBinary]
public class A : ISJSerializable
{public string name;public int age;public void Deserialize(SJBinaryReader reader){throw new System.NotImplementedException();}public void Serialize(SJBinaryWriter writer){throw new System.NotImplementedException();}
}
自动生成序列化方法
- 点击Unity顶部菜单栏:Tools -> SJBinary -> Generate Methods
- 系统将自动实现Deserialize和Serialize方法
生成的类结构如下:
[SJBinary]
public class B : ISJSerializable
{public string name;public int age;public void Serialize(SJBinaryWriter writer){writer.Write(this.name);writer.Write(this.age);}public void Deserialize(SJBinaryReader reader){this.name = reader.ReadString();this.age = reader.ReadInt32();}
}
实战示例
以下是一个完整的使用示例,展示了如何在Unity中使用SJBinary进行高效序列化和反序列化:
public class ErJinZhiSample : MonoBehaviour
{//优化前497 343msprivate List<byte[]> serializedData = new List<byte[]>();public List<TestA> deserializedObjects = new List<TestA>();private const int count = 100000;public Button btnLoad;public Button btnCreate;// 复用的 readerprivate SJBinaryReader reader;void Start(){btnLoad.onClick.AddListener(TestLoad);btnCreate.onClick.AddListener(TestCreate);}void TestCreate(){serializedData.Clear();var writer = new SJBinary.SJBinaryWriter(1024); // 可复用缓冲区Stopwatch sw = Stopwatch.StartNew();for (int i = 0; i < count; i++){writer.Reset(); // 复用缓冲区TestA obj = new TestA{age = i,name = $"Name_{i}",time = DateTime.Now.Ticks,actions = "Run,Jump",actionsList = new List<string> { "Run", "Jump", "Walk" },ids = new List<int> { 1, 2, 3 },pads = new List<int> { 10, 20, 30 }};obj.Serialize(writer);// 保存二进制数据(注意这里保存的是 ArraySegment 以避免复制)serializedData.Add(writer.GetBytes());}sw.Stop();UnityEngine.Debug.Log($"[Create] Created and serialized {count} objects in {sw.ElapsedMilliseconds} ms");}void TestLoad(){deserializedObjects.Clear();Stopwatch sw = Stopwatch.StartNew();for (int i = 0; i < count; i++){byte[] data = serializedData[i];// 复用 readerif (reader == null)reader = new SJBinary.SJBinaryReader(data);elsereader.SetBuffer(data, 0, data.Length);TestA obj = new TestA();obj.Deserialize(reader);deserializedObjects.Add(obj);}sw.Stop();UnityEngine.Debug.Log($"[Load] Deserialized {count} objects in {sw.ElapsedMilliseconds} ms");}
}
技术原理与优势
二进制序列化的优势
1.高效性能: 二进制格式避免了文本解析的复杂性,直接读写内存数据
2.紧凑体积: 二进制数据通常比等效的JSON文本小30%-50%
3.低GC开销: 通过缓冲区复用和零拷贝技术大幅减少垃圾回收压力
SJBinary的设计特点
1.简单集成: 只需添加注解和接口实现,无需复杂配置
2.代码生成: 提供工具自动生成序列化代码,减少手动编写错误
3.缓冲区复用: 支持读写缓冲区的复用,极大减少内存分配
4.类型安全: 编译时检查类型一致性,避免运行时错误
最佳实践建议
1.适当初始化缓冲区大小: 根据典型数据大小初始化缓冲区,避免频繁扩容
2.复用读写器实例: 特别是在循环中处理多个对象时
3.处理版本兼容性: 当数据结构变化时,需要考虑向后兼容性策略
4.异常处理: 在序列化和反序列化过程中添加适当的异常处理机制
适用场景
SJBinary特别适用于以下场景:
- 需要频繁序列化/反序列大量数据的游戏
- 对性能敏感的网络通信应用
- 需要持久化大量游戏状态的单机游戏
- 需要快速加载大型配置文件的应用程序
总结
SJBinary为Unity开发者提供了一个简单易用且高性能的二进制序列化解决方案。通过其简洁的API设计和高效的实现,它能够显著提升数据处理的性能,同时保持较低的内存开销。对于需要处理大量数据的Unity项目,SJBinary是一个值得考虑的轻量级解决方案。
如果您在使用过程中有任何建议或问题,欢迎在评论区留言反馈。我们将持续优化和改进这个框架,以满足更多开发场景的需求。