Unity 读取Excel表的内容

在我们的项目开发过程中,策划们可能会配置很多的数据在一些文本文本中,例如商城物品,随机名称等,往往这些数据会放在不同的Excel当中。那么我们程序就需要通过读取Excel的内容,已供程序使用。

所以这一篇就讲讲Unity如何读取Excel的内容的。

 

github:https://github.com/luckyWjr/Demo

 

准备

首先我们要用到Excel.dll,ICSharpCode.SharpZipLib.dll,System.Data.dll这些库,具体的下载地址如下:链接: https://pan.baidu.com/s/1NhY_VxmO233cp3N09VErNw 提取码: qc5k

接着就是创建一个需要读取的excel表(本Demo中叫Item.xlsx),如下,大家可以自己发挥哈

Unity 读取Excel表的内容_第1张图片

 

在后续的文章中,Unity 修改Excel表的内容,添加的修改Excel文件的内容。

 

目的

准备工作做完之后,我们要看看我们根据这个表,要的结果是什么?我们会把表中的内容读取到一个对应的class实例(ItemManager)中,然后将这个实例生成一个Asset如图:

Unity 读取Excel表的内容_第2张图片Unity 读取Excel表的内容_第3张图片

会发现这个Asset包含了表里的所有内容,然后我们就可以使用这个Asset来获取我们需要的数据。比如将这个Asset文件放在Resources文件夹下,用如下代码遍历:

ItemManager man = Resources.Load("DataAssets/Item");
foreach(Item i in man.dataArray) {
    Debug.Log(i.itemId+"---"+ i.itemName+"---"+ i.itemPrice);
}

打出的Log如下:

Unity 读取Excel表的内容_第4张图片

当然我们也可以将这个Asset打成一个ab包来读取。

 

知识点:

1.ScriptableObject:我们要将一个class的实例生成一个UnityEngine.Object文件,然后将这个Object生成为Asset文件,我们的class需要继承ScriptableObject。

2.Serializable:可以序列化一个类,使这个被序列化的对象在Inspector面板上显示, 并可以赋予相应的值

3.读取excel的操作和打包AB一样,不能在程序运行时执行,代码要放在Editor文件夹下。

 

定义类

我们首先需要定义两个类,第一个类用来存放每行的表数据(Item)该类需要添加Serializable字段,才能在Asset中显示数据

namespace Data{
	[System.Serializable]
	public class Item { 
		public uint itemId;
		public string itemName;
		public uint itemPrice;
	}
}

第二个类用来存放前者的数组即所有的表数据(ItemManager)。该类即要生成Object的类,需要继承ScriptableObject

namespace Data{
	public class ItemManager : ScriptableObject { 
		public Item[] dataArray;
	}
}

 

读取Excel表

首先当然要导入之前说的三个dll文件,然后我们在Editor文件夹下创建cs文件去实现读取Excel的操作。我们先定义一个类,里面存放我们需要的一些字段:

namespace EditorTool {

    public class ExcelConfig {
        /// 
        /// 存放excel表文件夹的的路径,本例xecel表放在了"Assets/Excels/"当中
        /// 
        public static readonly string excelsFolderPath = Application.dataPath + "/Excels/";

        /// 
        /// 存放Excel转化CS文件的文件夹路径
        /// 
        public static readonly string assetPath = "Assets/Resources/DataAssets/";
    }
}

然后我们写一个类用来读取Excel表的数据,并解析数据存放在上面讲到的Item[]当中:

namespace EditorTool {
    public class ExcelTool {

        /// 
        /// 读取表数据,生成对应的数组
        /// 
        /// excel文件全路径
        /// Item数组
        public static Item[] CreateItemArrayWithExcel(string filePath) {
            //获得表数据
            int columnNum = 0, rowNum = 0;
            DataRowCollection collect = ReadExcel(filePath, ref columnNum, ref rowNum);

            //根据excel的定义,第二行开始才是数据
            Item[] array = new Item[rowNum - 1];
            for(int i = 1; i < rowNum; i++) {
                Item item = new Item();
                //解析每列的数据
                item.itemId = uint.Parse(collect[i][0].ToString());
                item.itemName = collect[i][1].ToString();
                item.itemPrice = uint.Parse(collect[i][2].ToString());
                array[i - 1] = item;
            }
            return array;
        }

        /// 
        /// 读取excel文件内容
        /// 
        /// 文件路径
        /// 行数
        /// 列数
        /// 
        static DataRowCollection ReadExcel(string filePath, ref int columnNum, ref int rowNum) {
            FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

            DataSet result = excelReader.AsDataSet();
            //Tables[0] 下标0表示excel文件中第一张表的数据
            columnNum = result.Tables[0].Columns.Count;
            rowNum = result.Tables[0].Rows.Count;
            return result.Tables[0].Rows;
        }
    }
}

最后,我们将拿到的数据存放在ItemManager当中,并生成一个Asset:

namespace EditorTool {
    public class ExcelBuild : Editor {

        [MenuItem("CustomEditor/CreateItemAsset")]
        public static void CreateItemAsset() {
            ItemManager manager = ScriptableObject.CreateInstance();
            //赋值
            manager.dataArray = ExcelTool.CreateItemArrayWithExcel(ExcelConfig.excelsFolderPath + "Item.xlsx");

            //确保文件夹存在
            if(!Directory.Exists(ExcelConfig.assetPath)) {
                Directory.CreateDirectory(ExcelConfig.assetPath);
            }

            //asset文件的路径 要以"Assets/..."开始,否则CreateAsset会报错
            string assetPath = string.Format("{0}{1}.asset", ExcelConfig.assetPath, "Item");
            //生成一个Asset文件
            AssetDatabase.CreateAsset(manager, assetPath);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
}

这样我们就大功告成了!!!在Unity菜单项,选择我们自定义的菜单CustomEditor->CreateItemAsset。即可生成我们需要的Asset。

 

附加

备注:上面这种方法,我们自己手动根据对应的表写对应的类,然后针对性解析。但是如果我们有几十个表,那么就会显得很愚蠢。所以有个优化方案就是,我们在表中存好字段名称和字段类型,然后遍历所有的表读取这两个信息,用代码自动生成我们需要的.cs文件。当类都生成好后,再去遍历表解析数据,利用反射存入对应的类中,然后生成对应的Asset。

Unity 读取Excel表的内容_第5张图片

 

注意:在AssetDatabase.CreateAsset()中,我们要传的路径应该是"Assets/"开头的Unity路径,而不是Windows中的全路径,类似于"E://..."。否则会报如下错误:Couldn't create asset file!

Unity 读取Excel表的内容_第6张图片

 

注意:在ScriptableObject类中,基本数据类型以外的成员类型需要加 SerializeField 关键字,自定义数据类型被ScriptableObject对象使用的时候,该类需要加 Serializable 关键字。如果没有加的话生成的Asset资源Inspector窗口就无法看见对应数据。

 

补充:

System.Data.dll如果冲突的话,删除即可。

经测试发现,分以下两种情况:

1. 如果xlsx文件的后缀为.xlsx,读取的代码应该为

IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

若使用CreateBinaryReader读取,则在excelReader.AsDataSet();会报错NullReferenceException: Object reference not set to an instance of an object

2.如果xlsx文件的后缀为.xls,读取的代码应该为

IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);

若使用CreateOpenXmlReader读取,则在CreateOpenXmlReader处会报错ArgumentNullException: Value cannot be null.

 

你可能感兴趣的:(Unity)