如何检测BinaryFormatter序列化完成时机 避免游戏存档异常
解决BinaryFormatter存档写入未完成即退出导致的存档损坏问题
BinaryFormatter.Serialize() 本身是同步阻塞方法,只要这行代码执行返回,对象序列化的内存操作就已经全部完成,不存在序列化逻辑跑一半的情况。你遇到的存档失效问题本质是文件流缓冲区数据未强制落地、资源释放逻辑不完善导致的:
- 调用
Stream.Close()时,仅能保证.NET运行时层面的流缓冲区数据提交给操作系统,不会强制等待操作系统把缓存写入物理磁盘,此时立刻终止进程会导致文件只写入了部分内容 - 没有用托管逻辑释放流资源,一旦序列化过程中触发异常,文件流会被直接中断,留下损坏的半写存档文件
- 如果你的代码逻辑是调用存档方法后立刻执行退出,没有等待整个IO流程走完,也会加剧这个问题
修正后的可安全退出的存档实现
void ExecuteSaveAndQuit() { BinaryFormatter formatter = new BinaryFormatter(); // 用Path.Combine拼接路径,自动适配不同操作系统的路径分隔符 string savePath = Path.Combine(Application.persistentDataPath, "Gmaster.fun"); PlayerData saveData = new PlayerData(); // using块会在代码段执行结束后自动释放文件流资源,哪怕中途抛出异常也不会残留文件锁 using (FileStream writeStream = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None)) { formatter.Serialize(writeStream, saveData); // 关键:强制将所有层级的缓冲区(包括操作系统层面的文件缓存)写入物理磁盘 writeStream.Flush(flushToDisk: true); } // 代码执行到此处时,存档已经100%写入磁盘完成,可以安全触发退出 Application.Quit(); }
落地注意事项
- 不要把完整存档逻辑绑定到
OnApplicationQuit这类生命周期回调上,移动端、主机端系统给应用退出的预留时间通常只有1-2秒,大体积存档很容易写不完就被系统强杀。“保存并退出”按钮的逻辑要走主动触发:点击按钮后先弹出不可交互的保存中提示,等上述存档方法完全执行完毕再自动退出 - 可以加一层简单的存档校验:写完文件后可以立刻读一遍文件头,确认文件长度符合预期再走退出逻辑,进一步降低坏档概率
- 稳妥起见可以加备份机制:写入新存档前先把旧存档重命名为备份文件,新存档写入校验通过后再删除备份,就算遇到断电、强退等极端情况,下次启动也能读备份恢复
- 额外提一句:
BinaryFormatter存在已知的序列化安全漏洞,如果后续要做MOD支持、联网同步存档这类功能,建议替换为JsonUtility、MessagePack等更安全的序列化方案,纯本地单机存档使用没有问题
内容的提问来源于stack exchange,提问作者tok23
相关产品推荐
相关产品推荐

