Unity 将 XLSX 文件转换为 CSV 或 Json 文件

1.前言

在游戏开发和数据处理过程中,CSV(Comma-Separated Values)或者 Json 文件经常被用作配置文件或数据传输的中间格式。而许多数据往往最初存储在 Excel 的 XLSX 文件中。因此,将这些 XLSX 文件转换为 CSV 文件成为了一个常见需求。

2.Xlsx转成Csv

本文将介绍如何使用 Unity 和 NPOI 库来实现一个 XLSX 转 CSV 的工具,以及如何在 Unity 中解析 CSV 文件。

使用 NPOI 将 XLSX 文件转换为 CSV
首先,我们使用了 NPOI 库,它能够兼容 WPS 和不同版本的 Excel 文件。为了简化操作,我们通过 Unity 的 Editor 窗口创建了一个工具类 XlsxToCsv,它允许用户选择输入和输出路径,并定义 CSV 文件的行数限制。
关于NOPI库,已经放在Git的目录下在这里插入图片描述

1.文件路径的读取与保存

目前用OnGui实现一个简单的显示界面 

在这里插入图片描述

	string inputPath = "";
    string outputPath = "";
    int lineCount = 0;

    [MenuItem("XlsxTools/通用Xlsx to Csv")]
    public static void ShowWindow()
    {
        EditorWindow.GetWindow(typeof(XlsxToCsv));
    }

    Dictionary<string, string> csvFileOuts = new Dictionary<string, string>();
	
	//生成显示界面
    private void OnGUI()
    {
        GUILayout.Label("Base Settings", EditorStyles.boldLabel);

        if (GUILayout.Button("Select Input Path"))
        {
            string defaultPath = string.IsNullOrEmpty(inputPath) ? "" : inputPath;
            inputPath = EditorUtility.OpenFolderPanel("Select Input Folder", defaultPath, "");
        }

        EditorGUILayout.LabelField("Input Path: " + inputPath);

        if (GUILayout.Button("Select Output Path"))
        {
            string defaultPath = string.IsNullOrEmpty(outputPath) ? "" : outputPath;
            outputPath = EditorUtility.OpenFolderPanel("Select Output Folder", defaultPath, "");
        }

        EditorGUILayout.LabelField("Output Path: " + outputPath);

        lineCount = EditorGUILayout.IntField("Line Count: ", lineCount);

        if (GUILayout.Button("Convert"))
        {
        	//进行数据存储
            EditorPrefs.SetString("inputPathXTC", inputPath);
            EditorPrefs.SetString("outputPathXTC", outputPath);
            EditorPrefs.SetInt("lineCountXTC", lineCount);

            string projectPath = Application.dataPath.Replace('/', '\\');

            ConvertFiles(inputPath, outputPath);
        }
    }

    private void OnEnable()
    {
        inputPath = EditorPrefs.GetString("inputPathXTC", "");
        outputPath = EditorPrefs.GetString("outputPathXTC", "");
        lineCount = EditorPrefs.GetInt("lineCountXTC", 0);
    }

有了基本显示界面后要进行路径的匹配,使输出的子文件夹路径与输入的路径完全一致

 private void ConvertFiles(string inputPath, string outputPath)
    {
        string[] fileEntries = Directory.GetFiles(inputPath, "*.xlsx", SearchOption.AllDirectories);

        foreach (string fileName in fileEntries)
        {
            string subPath = Path.GetRelativePath(inputPath, fileName);

            string outputSubFolder = Path.GetDirectoryName(subPath);
            string outputFolderFullPath = Path.Combine(outputPath, outputSubFolder);
            Directory.CreateDirectory(outputFolderFullPath);

            string outputFileNameWithoutExtension = Path.GetFileNameWithoutExtension(subPath);
            string outputCsvFile = Path.Combine(outputFolderFullPath, outputFileNameWithoutExtension + ".csv");

            if (File.Exists(outputCsvFile))
            {
                File.Delete(outputCsvFile);
            }

            if (!csvFileOuts.ContainsKey(fileName))
            {
                csvFileOuts.Add(fileName, outputCsvFile);
            }
        }

        EachXlsxToCsv();
    }

2.将XLSX进行拷贝并生成CSV

在 ConvertXlsxToCsvAc 方法中,实现了对 XLSX 文件的解析,并将其转换为 CSV 格式。这个方法通过 NPOI 读取 Excel 文件内容,并根据指定的行数限制将数据分割为多个 CSV 文件。为了处理不同的 Excel 版本,代码中使用了 XSSFWorkbook 和 HSSFWorkbook 两种解析方式。

private void ConvertXlsxToCsvAc(string inputFileName, string outputFileName, int lineCount = 3)
{
    if (string.IsNullOrEmpty(inputFileName) || string.IsNullOrEmpty(outputFileName))
    {
        Debug.LogError("File paths cannot be null or empty.");
        return;
    }

    if (Path.GetFileName(inputFileName).StartsWith("~$"))
    {
        Debug.LogWarning("Skipping temporary file: " + inputFileName);
        return;
    }
	 //即便表格在打开的状态下,也可进行转表
    string tempFilePath = Path.GetTempFileName();
    File.Copy(inputFileName, tempFilePath, true);

    using (FileStream file = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read))
    {
        IWorkbook workbook = null;
        try
        {
            workbook = new XSSFWorkbook(file);
        }
        catch (Exception)
        {
         	//Excel2003 的表格,采用此格式读取
            workbook = new HSSFWorkbook(file);
        }

        ISheet sheet = workbook.GetSheetAt(0);

        int maxCellNum = 0;
        for (int i = sheet.FirstRowNum; i <= sheet.LastRowNum; i++)
        {
            IRow row = sheet.GetRow(i);
            if (row != null && row.LastCellNum > maxCellNum)
            {
                maxCellNum = row.LastCellNum;
            }
        }

        // 具体格式在Git地址中有完整实例
    }

    File.Delete(tempFilePath);
}

3.在 Unity 运行时解析 CSV 文件

除了将 XLSX 文件转换为 CSV,我们还实现了一个方法 ParseCsvConfig,用于在 Unity 中解析生成的 CSV 文件。该方法支持不同数据类型的映射,能够将 CSV 文件中的数据直接转换为游戏中使用的配置对象。

 	public List<T> ParseCsvConfig<T>(string[] csvContent, char delimiter = '\t') where T : new()
    {
        var result = new List<T>();
        var properties = typeof(T).GetProperties();

        for (int i = 3; i < csvContent.Length; i++) // 从第四行开始解析
        {
            var values = csvContent[i].Split(delimiter); // 根据你的数据格式分割,可能是逗号或其他字符

            var obj = new T();
            for (int j = 0; j < properties.Length; j++)
            {
                if (j < values.Length)
                {
                    var property = properties[j];
                    var value = values[j];
                    try
                    {
                        if (property.PropertyType == typeof(int))
                        {
                            property.SetValue(obj, int.Parse(value, CultureInfo.InvariantCulture));
                        }
                        else if (property.PropertyType == typeof(float))
                        {
                            property.SetValue(obj, float.Parse(value, CultureInfo.InvariantCulture));
                        }
                        else if (property.PropertyType == typeof(bool))
                        {
                            property.SetValue(obj, bool.Parse(value));
                        }
                        else if (property.PropertyType == typeof(string))
                        {
                            property.SetValue(obj, value);
                        }
                        else if (property.PropertyType == typeof(AchievementReward))
                        {
                            property.SetValue(obj, new AchievementReward(value));
                        }
                        else if (property.PropertyType == typeof(int[]))
                        {
                            var intArray = value.Split('|').Select(int.Parse).ToArray();
                            property.SetValue(obj, intArray);
                        }
                        else if (property.PropertyType == typeof(List<int>))
                        {
                            var intList = value.Split('|').Select(int.Parse).ToList();
                            property.SetValue(obj, intList);
                        }
                        else if (property.PropertyType == typeof(List<float>))
                        {
                            var intList = value.Split('|').Select(float.Parse).ToList();
                            property.SetValue(obj, intList);
                        }
                        // 可以根据需要添加更多类型转换
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Failed to set property {property.Name} with value {value}: {ex.Message}");
                    }
                }
            }
            result.Add(obj);
        }
        return result;
    }

4.获取到CSV文件数据

使用的话也很简单,去读到让在本地的CSV文件,然后配置需要接收的类,就可以正确读取到
可以用此方法读取本地的文件

 	public string ReadDataByResources(string _path)
    {
        TextAsset textAsset = Resources.Load<TextAsset>(_path);
        string content = string.Empty;
        if (textAsset)
        {
            content = Encoding.UTF8.GetString(textAsset.bytes);
        }
        else
        {
            Debug.LogError("not found json file");
        }

        if (content.Equals(string.Empty))
        {
            Debug.LogWarning("file not exit or empty");
        }
        content = content.TrimStart('\uFEFF');
        return content;
    }

进行调用

 	public List<LevelData> GetLevelItems()
    {
        string csvContent = ReadDataByResources("Csv/levels");
        var _configItems = ParseCsvConfigFromContent<LevelData>(csvContent, ',');
        return _configItems;
    }

3.Xlsx转成Json

将转表Json工具放在了Tool目录下,在unity中调用,输入跟输出路径,即可转出json

@echo off
chcp 65001
@SET EXCEL_FOLDER=%1     //xlsx路径
@SET JSON_FOLDER=%2		//json输出路径
@SET EXE_PATH=%3		//exe相对路径

@ECHO Converting excel files in folder %EXCEL_FOLDER% ...
for /f "delims=" %%i in ('dir /b /a-d /s %EXCEL_FOLDER%\*.xlsx') do (
    @echo   processing %%~nxi 
    @CALL "%EXE_PATH%" --excel "%%i" --json "%JSON_FOLDER%\%%~ni.json" --header 3 --exclude_prefix ! --cell_json true --array true
)

具体Unity中的实现

 	public void RunBatFile()//(string batFilePath, string inAndOutPath)//string excelFilePath, string outputFolder)
    {
        if (jsonFlors.Count <= 0)
        {
            return;
        }

        Process process = new Process();
        process.StartInfo.FileName = batFilePath;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true; // Redirect the standard error stream

        string inAndOutPath = jsonFlors[jsonFlors.Count - 1];

        process.StartInfo.Arguments = inAndOutPath;//"\"" + excelFilePath + "\" \"" + outputFolder + "\""; // pass the excel file path and output folder as arguments
        process.Start();

        string output = process.StandardOutput.ReadToEnd();
        string error = process.StandardError.ReadToEnd();

        process.WaitForExit();

        if (!string.IsNullOrEmpty(output))
        {
            UnityEngine.Debug.Log(output);
        }

        if (!string.IsNullOrEmpty(error))
        {
            UnityEngine.Debug.LogError(error);
        }

        jsonFlors.RemoveAt(jsonFlors.Count - 1);

        RunBatFile();
    }

其余部分包括Ongui显示等,与转CSV基本一致
在这里插入图片描述

4.总结

通过本文介绍的方法,您可以在 Unity 中就可实现 XLSX 到 CSV 文件的转换,并解析这些 CSV 文件用于游戏配置。无论是在开发工具链中使用,还是在运行时加载数据,这些功能都将提高开发的效率。希望本文对您在 Unity 中处理 Excel 数据有所帮助。

5.Git链接

https://github.com/1574735736/XlsxToJsonOrCsv

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值