unity直接从excel中读取数据

一、实现背景

唉,每个策划都有不一样的需求,这个策划需要我能够直接从excel读取数据存到全局数据管理类中,能怎么办,只能宠着!!!

同时策划还有一些另外的要求,表示excel表中的数据为"\"或“TODO"或空,则不读取,列首行为中文时整列也不读取。

源码获取:unity直接从excel中读取数据,暂存数据格式为dic<string,Object>资源-CSDN文库

二、实现过程

因为直接从excel读取到的数据没有层次,不像封装好的类,一层一层封装,所以需要一个实体类来暂时保存从excel读取到的数据,从而再转化成封装好的类数据。

本质上是通过类的反射来获取数据,从多个excel文件获取的多个sheet表,只要有表名与实体类名的映射,就能加载,同步加载所有文件并返回Dictionary<String,Object>格式的数据,string是表名,Object为List<表名对应的实体类>的装箱。

核心代码

public class ExcelImporter
{
    /// <summary>
    /// 加载Excel文件
    /// </summary>
    /// <param name="filePaths">多个文件路径</param>
    /// <param name="assembly">程序集</param>
    /// <param name="namespacePrefix">命名空间</param>
    /// <param name="sheetNameShiftDic">映射表</param>
    /// <returns></returns>
    public static Dictionary<string, System.Object> ImportExcelFiles(string[] filePaths, Assembly assembly, string namespacePrefix, Dictionary<string, string> sheetNameShiftDic)
    {
        Dictionary<string, System.Object> excelDatas = new Dictionary<string, System.Object>();
        foreach (var path in filePaths)
        {
            var excelName = Path.GetFileNameWithoutExtension(path);
            if (excelName.StartsWith("~$")) continue;
            IWorkbook book = LoadBook(path);
            Debug.Log("sheetCount:" + book.NumberOfSheets);
            for (int i = 0; i < book.NumberOfSheets; i++)
            {
                ISheet sheet = book.GetSheetAt(i);
                if (sheet == null) continue;
                if (!sheetNameShiftDic.ContainsKey(sheet.SheetName)) continue;
                string className = namespacePrefix + sheetNameShiftDic[sheet.SheetName];
                Type classType = assembly.GetType(className);
                if (classType == null)
                {
                    Debug.LogError("排除表:" + sheet.SheetName);
                    continue;
                }
                Debug.Log("加载表:" + sheet.SheetName);
                excelDatas.Add(sheet.SheetName, GetEntityListFromSheet(sheet, classType));

            }
        }
        return excelDatas;
    }

    public static IWorkbook LoadBook(string excelPath)
    {
        using (FileStream stream = File.Open(excelPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            if (Path.GetExtension(excelPath) == ".xls") return new HSSFWorkbook(stream);
            else return new XSSFWorkbook(stream);
        }
    }

    private static List<string> GetFieldNamesFromSheetHeader(ISheet sheet)
    {
        IRow headerRow = sheet.GetRow(0);

        var fieldNames = new List<string>();
        for (int i = 0; i < headerRow.LastCellNum; i++)
        {
            var cell = headerRow.GetCell(i);
            if (cell == null || cell.CellType == CellType.Blank) break;
            fieldNames.Add(cell.StringCellValue);
        }
        return fieldNames;
    }

    static object CellToFieldObject(ICell cell, FieldInfo fieldInfo, bool isFormulaEvalute = false)
    {
        var type = isFormulaEvalute ? cell.CachedFormulaResultType : cell.CellType;

        switch (type)
        {
            case CellType.String:
                if (fieldInfo.FieldType.IsEnum) return Enum.Parse(fieldInfo.FieldType, cell.StringCellValue);
                else return cell.StringCellValue;
            case CellType.Boolean:
                return cell.BooleanCellValue;
            case CellType.Numeric:
                return Convert.ChangeType(cell.NumericCellValue, fieldInfo.FieldType);
            case CellType.Formula:
                if (isFormulaEvalute) return null;
                return CellToFieldObject(cell, fieldInfo, true);
            default:
                if (fieldInfo.FieldType.IsValueType)
                {
                    return Activator.CreateInstance(fieldInfo.FieldType);
                }
                return null;
        }
    }

    static object CreateEntityFromRow(IRow row, List<string> columnNames, Type entityType, string sheetName)
    {
        var entity = Activator.CreateInstance(entityType);

        for (int i = 0; i < columnNames.Count; i++)
        {
            FieldInfo entityField = entityType.GetField(
                columnNames[i],
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
            );
            if (entityField == null) continue;
            if (!entityField.IsPublic && entityField.GetCustomAttributes(typeof(SerializeField), false).Length == 0) continue;

            ICell cell = row.GetCell(i);
            if (cell == null) continue;
            if (cell.CellType == CellType.String && cell.StringCellValue == "\\") continue;
            if (cell.CellType == CellType.String && cell.StringCellValue == "TODO") continue;
            try
            {
                object fieldValue = CellToFieldObject(cell, entityField);
                entityField.SetValue(entity, fieldValue);
            }
            catch
            {
                throw new Exception(string.Format("Invalid excel cell type at row {0}, column {1}, {2} sheet.", row.RowNum, cell.ColumnIndex, sheetName));
            }

        }
        return entity;
    }

    static object GetEntityListFromSheet(ISheet sheet, Type entityType)
    {
        List<string> excelColumnNames = GetFieldNamesFromSheetHeader(sheet);

        Type listType = typeof(List<>).MakeGenericType(entityType);
        MethodInfo listAddMethod = listType.GetMethod("Add", new Type[] { entityType });
        object list = Activator.CreateInstance(listType);

        // row of index 0 is header,row of index 1 is Chinese explaination
        for (int i = 2; i <= sheet.LastRowNum; i++)
        {
            IRow row = sheet.GetRow(i);
            if (row == null) break;

            ICell entryCell = row.GetCell(0);
            if (entryCell == null || entryCell.CellType == CellType.Blank) break;

            // skip comment row
            if (entryCell.CellType == CellType.String && entryCell.StringCellValue.StartsWith("#")) continue;

            var entity = CreateEntityFromRow(row, excelColumnNames, entityType, sheet.SheetName);
            listAddMethod.Invoke(list, new object[] { entity });
        }
        return list;
    }
}

三、测试过程

3.1 excel表

3.2 导入数据查看

3.3 其中一个实体类的数据转换

public class HexCellTypeInfoLoader
{
    public static Dictionary<HexCellTypeID, HexCellTypeInfo> LoadHexCellTypeInfo()
    {
        Dictionary<string, Object> datas = StaticDataLoader.StaticDatas;
        if(datas.ContainsKey("地块"))
        {
            return HexCellTypeInfoShift(datas["地块"]);
        }
        else return null;
    }

    private static Dictionary<HexCellTypeID, HexCellTypeInfo> HexCellTypeInfoShift(Object data)
    {
        List<HexCellTypeInfoEntity> entities = (List<HexCellTypeInfoEntity>)data;
        Dictionary<HexCellTypeID, HexCellTypeInfo> result = new Dictionary<HexCellTypeID, HexCellTypeInfo>();
        foreach(HexCellTypeInfoEntity entity in entities)
        {
            HexCellTypeID id = new HexCellTypeID(entity.UUID, entity.ID);
            HexCellTypeInfo info = new HexCellTypeInfo(id,entity);
            result.Add(id, info);
        }
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

winlife_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值