
适用场景:工业仿真、PLC 参数配置、单机工具存档;无需第三方插件,原生 API
目录
- 前言
- 基础原理
- 基础版:JSON 读写最简代码
- 进阶实战:TMP UI 输入 + 保存 / 读取按钮交互
- List 列表 JSON 存储方案
- 高频踩坑大全
- 优缺点总结
1. 前言
在 Unity 项目开发中,经常需要保存设备参数、配置信息。很多开发者直接引入Newtonsoft.Json,但中小型项目、工业仿真项目完全不需要第三方插件 。 Unity 内置JsonUtility,原生支持、跨平台、打包无冲突、轻量零依赖。
本文分为两大模块: ✅ 基础:通用 JSON 读写工具类 ✅ 进阶:结合 TMP 输入框、按钮,实现可视化配置保存加载
开发环境:Unity 2021+,TextMeshPro
整体结构:

2. 基础核心原理
核心 API
JsonUtility.ToJson(obj,prettyPrint:true)对象 → JSON 字符串JsonUtility.FromJson<T>(jsonString)JSON 字符串 → 对象
三条硬性规则(99% 报错根源)
- 数据模型类必须添加
[System.Serializable] - 需要序列化的字段必须标记为
public - JsonUtility不支持直接序列化顶层 List / 数组,需要包装类
路径选择
推荐路径:Application.persistentDataPath ✅ 编辑器、打包后均可读写 ❌ 禁止使用Application.dataPath,打包后只读,无法写入文件
3. 基础版代码实现
3.1 数据模型(PLC 配置示例)
cs
using System;
[Serializable]
public class PlcConfigData
{
public string Ip;
public int Rack;
public int Slot;
public float Speed;
public bool IsConnected;
}
3.2 通用静态 JSON 工具类(全局调用)
cs
using UnityEngine;
using System.IO;
public static class JsonTool
{
/// <summary>
/// 保存对象到JSON文件
/// </summary>
/// <typeparam name="T">数据模型</typeparam>
/// <param name="data">数据源</param>
/// <param name="filePath">完整保存路径</param>
public static void SaveJson<T>(T data, string filePath)
{
// prettyPrint=true 格式化输出json,方便手动查看
string jsonStr = JsonUtility.ToJson(data, true);
File.WriteAllText(filePath, jsonStr);
Debug.Log($"JSON保存成功:{filePath}");
}
/// <summary>
/// 读取JSON文件转为对象
/// </summary>
public static T LoadJson<T>(string filePath)
{
if (!File.Exists(filePath))
{
Debug.LogWarning("JSON配置文件不存在");
return default;
}
string jsonStr = File.ReadAllText(filePath);
return JsonUtility.FromJson<T>(jsonStr);
}
}
3.3 基础调用示例
cs
using UnityEngine;
using System.IO;
public class JsonTest : MonoBehaviour
{
private string SavePath => Path.Combine(Application.persistentDataPath, "plcConfig.json");
void Start()
{
// 构造测试数据
PlcConfigData data = new PlcConfigData()
{
Ip = "192.168.0.1",
Rack = 0,
Slot = 1,
Speed = 35.5f,
IsConnected = false
};
// 保存
JsonTool.SaveJson(data, SavePath);
// 读取
PlcConfigData loadData = JsonTool.LoadJson<PlcConfigData>(SavePath);
if (loadData != null)
{
Debug.Log("读取IP:" + loadData.Ip);
}
}
}
文件查找路径(Windows 编辑器)
cs
C:\Users\用户名\AppData\LocalLow\公司名称\项目名称\plcConfig.json
AppData 为隐藏文件夹,直接粘贴路径到资源管理器地址栏打开。
4. 进阶实战:TMP UI 可视化配置
需求:
- TMP 输入框填写 IP、机架、槽号、速度 2.【保存按钮】读取输入框内容,写入 JSON 3.【读取按钮】加载 JSON 数据,自动回填输入框
4.1 场景准备
在 Canvas 下创建 UI 组件:
- TMP_InputField ×4:IP 地址、机架号、槽号、速度
- Button ×2:【保存配置】、【读取配置】 将脚本挂载到场景物体,Inspector 面板拖拽绑定组件。
4.2 UI 交互完整脚本
cs
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using System.IO;
public class PlcConfigUI : MonoBehaviour
{
[Header("TMP输入框绑定")]
public TMP_InputField tmpIp;
public TMP_InputField tmpRack;
public TMP_InputField tmpSlot;
public TMP_InputField tmpSpeed;
[Header("按钮绑定")]
public Button btnSave;
public Button btnLoad;
// 配置文件路径
private string SavePath => Path.Combine(Application.persistentDataPath, "plcConfig.json");
void Start()
{
// 绑定按钮点击事件
btnSave.onClick.AddListener(OnSaveClick);
btnLoad.onClick.AddListener(OnLoadClick);
// 可选:启动游戏自动加载上次保存的参数
// OnLoadClick();
}
/// <summary>
/// 保存按钮回调:读取UI数据 → 写入JSON
/// </summary>
void OnSaveClick()
{
PlcConfigData config = new PlcConfigData();
config.Ip = tmpIp.text;
// TryParse安全转换,非法输入不会导致程序崩溃
int.TryParse(tmpRack.text, out config.Rack);
int.TryParse(tmpSlot.text, out config.Slot);
float.TryParse(tmpSpeed.text, out config.Speed);
JsonTool.SaveJson(config, SavePath);
Debug.Log("参数保存完成");
}
/// <summary>
/// 读取按钮回调:加载JSON → 回填UI输入框
/// </summary>
void OnLoadClick()
{
PlcConfigData config = JsonTool.LoadJson<PlcConfigData>(SavePath);
if (config == null)
{
Debug.LogError("配置文件不存在,无法读取!");
return;
}
tmpIp.text = config.Ip;
tmpRack.text = config.Rack.ToString();
tmpSlot.text = config.Slot.ToString();
tmpSpeed.text = config.Speed.ToString();
Debug.Log("参数读取成功,已回填界面");
}
private void OnDestroy()
{
// 移除监听,防止内存泄漏
btnSave.onClick.RemoveListener(OnSaveClick);
btnLoad.onClick.RemoveListener(OnLoadClick);
}
}
可选优化建议
- 限制输入框只能输入数字 选中 TMP InputField 组件 →
ContentType设置为Number - 启动自动加载 取消 Start 函数中
OnLoadClick()的注释 - 新增 TMP 文本组件,展示「保存成功 / 失败」提示
保存数据:

保存效果:

修改数据:

读取数据:

5. List 列表数据存储方案
问题
JsonUtility 不支持直接序列化顶层数组 / List,会报错。
解决方案:外层包装类
cs
using System;
using System.Collections.Generic;
[Serializable]
public class DataListWrapper
{
public List<PlcConfigData> DataList;
}
使用示例
cs
//保存列表
DataListWrapper wrapper = new DataListWrapper();
wrapper.DataList = new List<PlcConfigData>();
wrapper.DataList.Add(new PlcConfigData() { Ip = "192.168.0.2", Rack = 0, Slot = 2 });
JsonTool.SaveJson(wrapper, SavePath);
//读取列表
DataListWrapper loadWrap = JsonTool.LoadJson<DataListWrapper>(SavePath);
if (loadWrap != null)
{
foreach (var item in loadWrap.DataList)
{
Debug.Log(item.Ip);
}
}
6. 高频踩坑大全
-
❌ 数据类缺少
[Serializable]现象:生成空 json{},读取所有字段为空,无报错 ✅ 解决方案:必须添加序列化标签 -
❌ 字段使用 private 修饰 现象:字段无法序列化,json 看不到数据 ✅ 解决方案:序列化字段使用 public
-
❌ 保存后立刻读取,偶尔读取失败 原因:操作系统磁盘写入延迟 ✅ 解决方案:使用协程延迟读取
-
❌ 尝试序列化 Dictionary 原生 JsonUtility 不支持字典,方案:改用 List 键值对模型 / Newtonsoft.Json
-
❌ 使用
Application.dataPath做存档路径 打包后目录只读,无法创建文件,必须使用persistentDataPath
7. 优缺点总结
✅ 优点
- 零第三方插件,原生自带,无版本冲突
- 跨平台兼容 Windows / Android / IOS
- 轻量高效,工业仿真、工具项目完全够用
❌ 缺点
- 不支持顶层数组、List
- 原生不支持 Dictionary 类型