4.总结
4.1 知识点

实践小项目做了什么

问题抛出

问题解决

4.2 核心要点速览
项目在做什么
业务脚本只面对一个入口:JsonDataMgr.Instance。它把「对象 ↔ Json 文本 ↔ 磁盘文件」三件事收进管理器:对外是保存任意 object、按文件名加载成 T,内部再决定落盘路径和用哪套序列化 API。
本课要落地的能力:单例管理器;JsonType 在 JsonUtility 与 LitJson 之间切换;SaveData / LoadData 的默认方案与课内代码一致,默认走 LitJson。
路径策略:为什么读要「先包内、再本地」,写只往 persistent
- SaveData:路径固定为
Application.persistentDataPath + "/" + fileName + ".json"。这是运行时可写目录,适合存档、下载配置、玩家改过的表。 - LoadData:先拼
Application.streamingAssetsPath下的同名文件;不存在再换Application.persistentDataPath。典型用法是 StreamingAssets 里放随包发布的默认 Json,persistent 里放 覆盖版或用户存档;先读包内底稿,没有再落到用户目录。 - 都没有:直接
return new T(),所以泛型必须where T : new(),否则无法在无文件时安全构造默认对象。
| 步骤 | 目录根 | 用途直觉 |
|---|---|---|
| 保存 | persistentDataPath | 需要写入、可覆盖的文件 |
| 读取优先 | streamingAssetsPath | 只读、随包资源 |
| 读取回退 | persistentDataPath | 本地生成或已修改的副本 |
JsonType 与分支里的 API
switch (type) 里两套调用必须成对使用;存的时候用 LitJson、读的时候误选 JsonUtility,很容易得到空字段或解析异常。
| JsonType | 序列化 | 反序列化 |
|---|---|---|
| JsonUtility | JsonUtility.ToJson |
JsonUtility.FromJson<T> |
| LitJson | JsonMapper.ToJson |
JsonMapper.ToObject<T> |
课里默认参数是 JsonType.LitJson,因此工程里必须带 LitJson 源码或引用,导出包时也要一并勾选,否则别的项目导入后会缺类型。
管理器最小骨架
public class JsonDataMgr
{
private static JsonDataMgr instance = new JsonDataMgr();
public static JsonDataMgr Instance => instance;
private JsonDataMgr() { }
// SaveData / LoadData:见系列正文完整实现
}
私有构造拦住 new JsonDataMgr(),只保留 Instance 单入口,避免场景里挂多个管理器各写各的文件。
4.3 面试题精选
进阶题
1. 保存和读取为什么用不同的路径策略
题目
SaveData 为什么只往 Application.persistentDataPath 写,而 LoadData 要先查 Application.streamingAssetsPath 再回退到 persistent?
深入解析
- 写:StreamingAssets 在多数平台是只读或不适合运行时改写;持久化存档、玩家配置必须落在可写目录,persistent 是 Unity 提供的跨平台可写沙箱路径。
- 读:包内默认数据随安装走,适合放 StreamingAssets;用户下载补丁、本地改键位、存档则落在 persistent。先读包内再读本地,等于「默认表 + 用户覆盖」的常见组合。
- 面试收口:一句话说清「写要可写、读要先只读后可写」,再各举一个游戏里的例子即可。
答题示例
保存必须写到运行时允许改写的目录,所以课里用 persistentDataPath。
读取先找 StreamingAssets,一般是随包的默认 Json;没有再用 persistent,对应存档或本地覆盖。这样发布默认配置和玩家数据能分到两个目录里。
参考文章
- 2.Json数据管理类存储和读取数据
2. JsonType 枚举解决了什么问题
题目
为什么要单独做 JsonType 枚举,并把默认方案设为 LitJson?
深入解析
- 工程意义:同一套业务接口下可以切换序列化实现,方便对比、迁移或按平台选实现,而不是把
JsonUtility/JsonMapper写死在调用点。 - 默认 LitJson:课内管理器代码默认走 LitJson 分支,与项目里引入的 LitJson 源码一致;若默认改成
JsonUtility却未改依赖,会造成「代码默认」和「工程引用」错位。 - 注意点:存和读必须选同一种
JsonType,否则格式细节不一致会直接反序列化失败。
答题示例
枚举把「用哪套库」变成显式参数,Save 和 Load 可以统一切换。
默认 LitJson 是因为项目里集成了 LitJson,管理器示例按这个依赖来写;真正项目里默认值要跟包内引用一致,而且读写要用同一个枚举值。
参考文章
- 2.Json数据管理类存储和读取数据
3. 泛型约束与无文件时的返回值
题目
LoadData<T> 为什么要写 where T : new()?和「文件不存在就 return new T()」是什么关系?
深入解析
- 编译期:
new T()要求编译器知道T有无参构造;where T : new()是 C# 对该写法的约束。 - 语义:无文件时返回「默认空对象」而不是
null,调用方可以少写一层 null 判断,但要清楚空对象和「有文件但字段全默认」在数据上可能无法区分。 - 延伸:若类型只有带参构造或单例,不能直接套这个写法,需要改工厂或默认值策略。
答题示例
new T()要求 T 能无参构造,所以要加where T : new()。找不到文件时返回
new T(),相当于给调用方一个「空档」而不是 null,用起来简单;但要心里有数,这和「读了文件但内容全是默认值」可能长得一样。
参考文章
- 2.Json数据管理类存储和读取数据
4. 导出包为什么要带上 LitJson
题目
生成 unitypackage 给别的工程用时,为什么要强调把 LitJson 文件夹一起导出?
深入解析
- 依赖关系:
JsonMapper等类型来自 LitJson,不把源码或程序集打进包,导入方会大量编译错误。 - 操作层面:在导出树里勾选整个 LitJson 目录,并善用「包括依赖项」,避免只勾了
JsonDataMgr.cs漏掉库。 - 对比:若项目只用
JsonUtility,则不必带 LitJson;一旦默认分支是 LitJson,包内容必须与之一致。
答题示例
管理器默认用 LitJson 的 API,LitJson 是外部脚本库,不导出的话别的工程没有
JsonMapper这些类。所以导出时要勾选整个 LitJson 目录,最好开包括依赖项,和课里截图一致。
参考文章
- 3.生成资源包
深度题
1. 同名 Json 在两处都存在时读哪一份
题目
若 fileName.json 同时存在于 streamingAssetsPath 与 persistentDataPath,当前课内 LoadData 会读哪一边?这种优先级适合什么业务?
深入解析
- 代码路径:先赋值 StreamingAssets 全路径,
File.Exists为真则不会再切到 persistent,因此永远读包内那份。 - 业务含义:适合「包内是只读母版,只有包内没有该文件时才用本地生成的」;若期望「本地永远覆盖包内」,课内逻辑需要改成先查 persistent 或合并策略,而不是照抄当前顺序。
- 踩坑:策划若以为改 persistent 里文件能覆盖包内同名表,在当前实现下不会生效。
答题示例
会先检查 StreamingAssets,存在就直接读,不会读到 persistent。
适合包内带默认配置、本地只在「没有包内文件」时才生效的场景。如果要玩家覆盖版一定优先,就要调整判断顺序或加版本号分流。
参考文章
- 2.Json数据管理类存储和读取数据
2. 同步读写 API 的边界
题目
课里用 File.WriteAllText 和 File.ReadAllText 一次性读完、写完整个 Json 文件。在什么情况下这可能成为问题?可以怎么演进?
深入解析
- 主线程阻塞:文件较大或移动设备存储慢时,同步 IO 可能造成明显卡顿或掉帧;Unity 主线程做重 IO 是常见性能雷点。
- 内存峰值:
ReadAllText一次性把字符串载入内存,超大表会拉高峰值。 - 演进方向:拆分为异步 API、分帧加载、或边读边解析的流式方案;存档类小文件通常仍可接受同步写法。
- 答题边界:不必展开所有平台差异,点到「主线程 + 大文件」即可。
答题示例
同步读写会在主线程上等磁盘,文件大或设备慢时会卡帧。
小存档一般没问题;配置表很大时可以考虑异步、分块读或流式解析。WriteAllText、ReadAllText 适合课里先把逻辑讲清楚,上线要按体量评估。
参考文章
- 2.Json数据管理类存储和读取数据
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com