Unity(C#)将json数据存储到Excel(.csv)文件中

本文介绍了一个将JSON数据转换为CSV文件的方法,适用于游戏策划查看游戏中战斗数值的需求。使用Unity和C#实现,涉及Newtonsoft.Json.dll进行反序列化。

网上找了很多将json数据存储到Excel(.csv)文件的实现方案,发现要么语言不适用,要么需要的库文件难找或者导入Unity项目又冲突,再或者就是直接在线转换工具还需要钱等等坑,于是下定决心自己搞一个出来,当真是不容易啊。

背景:策划想要直观的查看游戏中的战斗数值,将战斗数据输出到Excel表中;
工具:Unity,C#,Newtonsoft.Json.dll(反序列化json数据要用的库文件);

动态链接库bd网盘下载地址:https://pan.baidu.com/s/1Mz_Kvv21S1zNojkDIn4NLA
密码:yi7s

核心demo代码:

using System.Collections.Generic;
using System.Data;
using System.IO;
using UnityEngine;
using Newtonsoft.Json;
using System.Reflection;
using System;

[Serializable]
public class Job
{
    public string jobName;
    public int salary;
}

[Serializable]
public class Person
{
    //直接使用字段
    public string name; //属性写法加上:{ get; set; }
    public string native; //属性写法加上:{ get; set; }
    public int age; //属性写法加上:{ get; set; }
    public Job job;
}

public class JsonToExcel
{
    //json  转 DataTable  类型   然后导出  excel
    //参数1 string json json数据 参数2 tabName导出成Excel后的名称(不需要带.csv后缀,后面加上了)
    public static void JsonToCsv(string json, string path)
    {
        //json数据转成  DataTable   类型
        DataTable dataTab = JsonToDataTable<Person>(json);
        //DataTable数据存储到 .csv 表
        DataTableToCsv(dataTab, path);//不会跳转单元格,每一行的数据在一个单元里面
    }

    //json  转 DataTable
    private static DataTable JsonToDataTable<T>(string json)
    {
        DataTable dataTable = new DataTable(); //实例化
        DataTable result;
        try
        {
            List<T> arrayList = JsonConvert.DeserializeObject<List<T>>(json);
            if (arrayList.Count <= 0)
            {
                result = dataTable;
                return result;
            }

            foreach (T item in arrayList)
            {
                Dictionary<string, object> dictionary = GetFields<T>(item);//如果Test类中的都是属性就使用GetProperties方法获取dictionary
                //Columns
                if (dataTable.Columns.Count == 0)
                {
                    foreach (string current in dictionary.Keys)
                    {
                        Debug.Log("增加一列:" + current + ",类型:" + dictionary[current].GetType());
                        dataTable.Columns.Add(current, dictionary[current].GetType());
                    }
                }
                //Rows
                DataRow dataRow = dataTable.NewRow();
                foreach (string current in dictionary.Keys)
                {
                    Debug.Log("增加一行:" + current + " =" + dictionary[current]);
                    dataRow[current] = dictionary[current];
                }
                dataTable.Rows.Add(dataRow); //循环添加行到DataTable中
            }
        }
        catch
        {

        }
        result = dataTable;
        return result;
    }

    //导出Excel
    private static void DataTableToCsv(DataTable table, string file)
    {
        file = file + ".csv";
        if (File.Exists(file))
        {
            File.Delete(file);
        }
        if (table.Columns.Count <= 0)
        {
            Debug.LogError("table.Columns.Count <= 0");
            return;
        }

        string title = "";
        FileStream fs = new FileStream(file, FileMode.OpenOrCreate);
        //StreamWriter sw = new StreamWriter(new BufferedStream(fs), System.Text.Encoding.Default);//这个中文会乱码
        StreamWriter sw = new StreamWriter(new BufferedStream(fs), System.Text.Encoding.UTF8);
        for (int i = 0; i < table.Columns.Count; i++)
        {
            //title += table.Columns[i].ColumnName + "\t"; //栏位:自动跳到下一单元格,然而我这里运行后并没有
            title += table.Columns[i].ColumnName + ","; //栏位:自动跳到下一单元格,老铁没毛病
        }

        title = title.Substring(0, title.Length - 1) + "\n";
        sw.Write(title);
        foreach (DataRow row in table.Rows)
        {
            string line = "";
            for (int i = 0; i < table.Columns.Count; i++)
            {
                //line += row[i].ToString().Trim() + "\t"; //内容:自动跳到下一单元格,然而我这里运行后并没有
                line += row[i].ToString().Trim() + ","; //内容:自动跳到下一单元格,老铁没毛病
            }
            line = line.Substring(0, line.Length - 1) + "\n";
            sw.Write(line);
        }
        sw.Close();
        fs.Close();
    }

    /// <summary>
    ///  使用反射机制获取类中的字段-值列表:只获取一层的,不获取子对象的字段
    /// </summary>
    /// <returns>所有字段名称</returns>
    public static Dictionary<string, object> GetFields<T>(T t)
    {
        Dictionary<string, object> keyValues = new Dictionary<string, object>();
        if (t == null)
        {
            return keyValues;
        }
        System.Reflection.FieldInfo[] fields = t.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
        if (fields.Length <= 0)
        {
            return keyValues;
        }
        foreach (System.Reflection.FieldInfo item in fields)
        {
            string name = item.Name; //名称
            object value = item.GetValue(t);  //值

            if (item.FieldType.IsValueType || item.FieldType.Name.StartsWith("String"))
            {
                keyValues.Add(name, value);
            }
            else
            {
                Debug.Log("值类型:" + value.GetType().Name);
                //递归将子类中的字段加入进来
                Dictionary<string, object> subKeyValues = GetFields<object>(value);
                foreach (KeyValuePair<string, object> temp in subKeyValues)
                {
                    keyValues.Add(temp.Key, temp.Value);
                }
            }
        }
        return keyValues;
    }

    /// <summary>
    /// 使用反射机制获取类中的属性-值列表:只获取一层的,不获取子对象的属性
    /// </summary>
    /// <returns>所有属性名称</returns>
    public static Dictionary<string, object> GetProperties<T>(T t)
    {
        Dictionary<string, object> keyValues = new Dictionary<string, object>();
        if (t == null)
        {
            return keyValues;
        }
        System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
        if (properties.Length <= 0)
        {
            return keyValues;
        }
        foreach (System.Reflection.PropertyInfo item in properties)
        {
            string name = item.Name; //名称
            object value = item.GetValue(t, null);  //值

            if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
            {
                keyValues.Add(name, value);
            }
            else
            {
                Debug.Log("值类型:" + value.GetType().Name);
                //递归将子类中的字段加入进来
                Dictionary<string, object> subKeyValues = GetProperties<object>(value);
                foreach (KeyValuePair<string, object> temp in subKeyValues)
                {
                    keyValues.Add(temp.Key, temp.Value);
                }
            }
        }
        return keyValues;
    }
}

测试代码:

        //JsonToExcel.jsonToDataTable("{'name':'老张', 'native':'湖北', 'age':46}", Application.dataPath + "/aaa");//不行,必须得是数组形式(最外围是[]包围的)
        //JsonToExcel.jsonToDataTable("[{'name':'老杨', 'native':'湖南', 'age':36},{'name':'老张', 'native':'湖北', 'age':46}]", Application.dataPath + "/aaa");//可以
        //JsonToExcel.jsonToDataTable("[{'name':'老杨', 'native':'湖南', 'age':36, {'jobName':'搬砖程序', 'salary':100}},{'name':'老张', 'native':'湖北', 'age':46, {'jobName':'农名程序', 'salary':50}}]", Application.dataPath + "/aaa");//不行,json格式错误,子对象也要有名字,对比下面少了job
        JsonToExcel.JsonToCsv("[{'name':'老杨', 'native':'湖南', 'age':36, 'job':{'jobName':'搬砖程序', 'salary':100}},{'name':'老张', 'native':'湖北', 'age':46, 'job':{'jobName':'农名程序', 'salary':50}}]", Application.dataPath + "/aaa");//可以(这里有子对象的数据,打包到excel表中后会将子类中所有字段或者属性都作为标头)

生成了我想要的.csv文件,没有乱码、能正常换行跳转单元存储:
在这里插入图片描述
后面正式的操作,只需要将要存储的数据形式,封装成一个类替换咱的Person类就好啦!
完成!!!

Unity 中使用 JSON 进行数据存储是一种常见且灵活的方式,尤其适用于需要结构化存储配置数据、玩家进度、关卡信息等场景。以下是 Unity 中使用 JSON 数据存储的方法及最佳实践。 ### 数据存储流程 在 Unity 中实现 JSON 数据存储通常包括以下步骤: 1. **定义数据结构**:创建一个类或结构体来表示需要存储的数据。例如,可以定义一个 `FishData` 类来保存鱼类的属性: ```csharp [System.Serializable] public class FishData { public string name; public int id; public float speed; } ``` 2. **序列化为 JSON 字符串**:使用 Unity 自带的 `JsonUtility.ToJson()` 方法将对象换为 JSON 格式字符串: ```csharp FishData fish = new FishData { name = "Clownfish", id = 1, speed = 0.5f }; string json = JsonUtility.ToJson(fish); ``` 3. **写入文件**:将 JSON 字符串写入本地文件系统。可以使用 `File.WriteAllText()` 方法将数据保存到指定路径: ```csharp string path = Application.persistentDataPath + "/fishData.json"; File.WriteAllText(path, json); ``` 4. **读取文件内容**:从文件中读取 JSON 数据并换为字符串: ```csharp string jsonStr = File.ReadAllText(path); ``` 5. **反序列化为对象**:将 JSON 字符串换回对象: ```csharp FishData loadedFish = JsonUtility.FromJson<FishData>(jsonStr); ``` ### 使用第三方库增强功能 Unity 自带的 `JsonUtility` 虽然简单易用,但功能有限,例如不支持嵌套对象或集合类型。为了更强大的功能,可以引入第三方库: - **LitJson**:支持复杂对象结构和集合类型,适合需要深度解析的场景[^5]。 - **Newtonsoft.Json (Json.NET)**:功能最强大,支持 LINQ、泛型、动态类型等,适合需要高性能和复杂序列化的项目。 使用 LitJson 示例: ```csharp using LitJson; string json = JsonMapper.ToJson(fish); FishData loadedFish = JsonMapper.ToObject<FishData>(json); ``` ### 路径选择与平台兼容性 Unity 提供了多个路径常量用于文件操作,例如: - `Application.dataPath`:只读路径,适合资源加载。 - `Application.persistentDataPath`:可读写路径,适合存储用户数据。 - `Application.streamingAssetsPath`:只读路径,适合预置资源[^3]。 注意:`File` 类在 `UnityEngine.Windows` 命名空间中,仅适用于 Windows 平台。在其他平台(如 Android 或 iOS)上,应使用 `Application.persistentDataPath` 等通用路径。 ### 编码与解码处理 在某些情况下,JSON 数据可能包含 Unicode 编码字符,需要进行解码处理: ```csharp using System.Text.RegularExpressions; string jsonDate = "{\"name\":\"\\u6D4B\\u8BD5\"}"; Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})"); jsonDate = reg.Replace(jsonDate, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString()); ``` ### 工具类封装(JsonMgr) 为了简化 JSON 的序列化和反序列化过程,可以封装一个 `JsonMgr` 工具类: ```csharp public static class JsonMgr { public static string Serialize<T>(T obj) { return JsonUtility.ToJson(obj); } public static T Deserialize<T>(string json) { return JsonUtility.FromJson<T>(json); } public static void SaveToFile(string path, string json) { File.WriteAllText(path, json); } public static string LoadFromFile(string path) { return File.Exists(path) ? File.ReadAllText(path) : null; } } ``` 使用方式: ```csharp FishData fish = new FishData { name = "Clownfish", id = 1, speed = 0.5f }; string json = JsonMgr.Serialize(fish); JsonMgr.SaveToFile(Application.persistentDataPath + "/fishData.json", json); string loadedJson = JsonMgr.LoadFromFile(Application.persistentDataPath + "/fishData.json"); FishData loadedFish = JsonMgr.Deserialize<FishData>(loadedJson); ``` ### 最佳实践总结 - **选择合适库**:根据项目复杂度选择 `JsonUtility`、`LitJson` 或 `Json.NET`。 - **路径选择**:优先使用 `Application.persistentDataPath` 以确保跨平台兼容性。 - **数据结构设计**:合理设计类或结构体,避免嵌套过深或复杂类型。 - **异常处理**:在读写文件时添加异常处理,避免程序崩溃。 - **工具类封装**:使用 `JsonMgr` 等工具类统一管理 JSON 操作,提高代码复用性。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值