EPPlus实战篇——Excel读取

.net core 项目

可以从excel读取任何类型(T)的数据,只要T中的field的[Display(Name = "1233")]中的name==excel column header's name

引用的nuget包:

1.EPPlus.Core

2. System.ComponentModel.Annotations

//类定义

public class ExcelReadServiceAccordingDisplayAttr<T> : IExcelReadService<T> where T : new()

{

    ILogBase _logger;

    static Dictionary<string, PropertyInfo> _displayAttrDic;

    public ExcelReadServiceAccordingDisplayAttr(ILogBase logBase)

    {

        _logger = logBase;

    }

 }

 class ExcelReadServiceAccordingDisplayAttr<T>中方法:

private List<T> GetData(string excelPath, string sheetName = ""int sheetIndex = 0)

{

    try

    {

        FileInfo existingFile = new FileInfo(excelPath);

        using (ExcelPackage package = new ExcelPackage(existingFile))

        {

            ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);

            if (sheet == nullreturn null;

            //获取不需要读取的column

            List<long> excluedeColumns = GetExcludeCloumns(sheet);

            //根据excelheader来获取type T数据对象的列字典

            Dictionary<int, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);

            //读取excel数据,填充List<T>

            List<T> result = GetDatesFromContent(sheet, columnIndexDic, excluedeColumns);

            return result;

        }

    }catch(Exception ex)

    {

        _logger.Error($"get data from excel exception :{ex.ToString()},excel:{excelPath},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}");

        throw ex;

    }

}

private List<T> GetDateFromSheet(ExcelWorksheet sheet)

 {

     if (sheet == nullreturn null;

     List<long> excluedeColumns = GetExcludeCloumns(sheet);

     //根据excelheader来获取type T数据对象的列字典

     Dictionary<int, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);

     //读取excel数据,填充List<T>

     List<T> result = GetDatesFromContent(sheet, columnIndexDic);

     return result;

 }

 private List<T> GetData(byte[] excelContent, string sheetName = ""int sheetIndex = 0)

 {

     try

     {

         using (Stream stream = new MemoryStream(excelContent))

         {

             using (ExcelPackage package = new ExcelPackage(stream))

             {

                 ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);

                 return GetDateFromSheet(sheet);

             }

         }

     }

     catch (Exception ex)

     {

         _logger.Error($"get data from excel exception :{ex.ToString()},excelContent:{excelContent},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}");

         throw ex;

     }

 }

 private ExcelCheckResult CheckDate(byte[] excelContent, string sheetName = ""int sheetIndex = 0)

 {

     try

     {

         using (Stream stream = new MemoryStream(excelContent))

         {

             using (ExcelPackage package = new ExcelPackage(stream))

             {

                 ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);

                 if (sheet == nullreturn null;

                 List<long> excluedeColumns = GetExcludeCloumns(sheet);

                 //根据excelheader来获取type T数据对象的列字典

                 Dictionary<int, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);

                 bool formatResult=FormatSheet(ref sheet, columnIndexDic);

                 package.Save();

                 if (!formatResult)

                 {

                     return new ExcelCheckResult() { CheckResult = false, CheckMsg = "format error!" };

                 }

                 return CheckExcel(ref sheet, columnIndexDic);

             }

         }

     }

     catch (Exception ex)

     {

         _logger.Error($"get data from excel exception :{ex.ToString()},excelContent:{excelContent},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}");

         throw ex;

     }

 }

 /// <summary>

 /// 根据 DisplayAttribute 的 Description 来格式化sheet

 /// </summary>

 /// <param name="sheet"></param>

 /// <param name="columnIndexDic"></param>

 private bool FormatSheet( ref ExcelWorksheet sheet, Dictionary<int, PropertyInfo> columnIndexDic)

 {

     try

     {

         var typeOfObject = typeof(T);

         var columnIndexDicForDisplayAttr = new Dictionary<int, DisplayAttribute>();

         foreach (var columnInfo in columnIndexDic)

         {

             int columnKey = columnInfo.Key;

             PropertyInfo columnProperty = columnInfo.Value;

             var attr = columnProperty.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;

             if (attr != null && !string.IsNullOrEmpty(attr.Description))

             {

                 var originalFormat = sheet.Column(columnKey).Style.Numberformat.Format;

                 sheet.Column(columnKey).Style.Numberformat.Format = attr.Description;

                 _logger.Warn($"change cloumn{columnKey} formate({ originalFormat}=>{attr.Description}):(class:{typeOfObject.FullName},property:{columnProperty.Name})");

             }

         }

         return true;

     }

     catch (Exception ex)

     {

         _logger.Error($"excel Format error. columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}", ex);

         return false;

     }

 }

 private ExcelCheckResult CheckExcel(ref ExcelWorksheet sheet, Dictionary<int, PropertyInfo> columnIndexDic)

 {

     var excelCheckResult = new ExcelCheckResult() {

         CheckResult=true,

         CheckMsg="Succeed!"

     };

     var columnPropertyDic = columnIndexDic.Values.ToLookup(p=>p.Name).ToDictionary(kp => kp.Key, kp => kp.FirstOrDefault());

     Dictionary<string, PropertyInfo> requiredPropertyDic= GetRequireDicFromType();

     StringBuilder msg = new StringBuilder();

     foreach (var requiredProperty in requiredPropertyDic)

     {

         var properName = requiredProperty.Key;

         if (!columnPropertyDic.ContainsKey(properName))

         {

             msg.AppendLine($"{properName} is required!");

             _logger.Warn($"property:({properName}) is required ! columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}");

         }

     }

     if (!string.IsNullOrEmpty(msg.ToString()))

     {

         excelCheckResult.CheckResult = false;

         excelCheckResult.CheckMsg = msg.ToString();

     }

     return excelCheckResult;

 }

 private Dictionary<string, PropertyInfo> GetRequireDicFromType()

 {

     Type typeOfObject = typeof(T);

     var pds = typeOfObject.GetProperties();

     if (pds == nullreturn null;

     var propertyDic = pds.ToLookup(p => {

         var attr = p.GetCustomAttribute(typeof(RequiredAttribute)) as RequiredAttribute;

         if (attr == nullreturn "";

         return p.Name;

     }).ToDictionary(kp => kp.Key, kp => kp.FirstOrDefault());

     if (propertyDic == null || propertyDic.Count() == 0)

     {

         _logger.Warn($"no RequireDic can get from class Type:{typeOfObject.FullName} ");

     }

     else

     {

         propertyDic.Remove("");

     }

     return propertyDic;

 }

private List<long> GetExcludeCloumns(ExcelWorksheet sheet)

{

    List<long> excludeCloumns = new List<long>();

    if (sheet.PivotTables == nullreturn excludeCloumns;

    //排除sheet中透视表的列

    foreach (var povotTable in sheet.PivotTables)

    {

        var startCloumn = povotTable.Address.Start.Column;

        var endColumn= povotTable.Address.End.Column;

        while (startCloumn <= endColumn)

        {

            excludeCloumns.Add(startCloumn);

            startCloumn++;

        }

    }

    return excludeCloumns;

}

private ExcelWorksheet GetSheet(ExcelPackage package, string sheetName,int sheetIndex)

{

    if (package == null || package.Workbook == null || package.Workbook.Worksheets == null || package.Workbook.Worksheets.Count == 0) return null;

    ExcelWorksheets excelWorksheets = package.Workbook.Worksheets;

    if (!string.IsNullOrWhiteSpace(sheetName))

    {

        var targetSheet = excelWorksheets.Where(s => s.Name.ToLower().Trim() == sheetName.ToLower());

        if (targetSheet == null || targetSheet.Count() == 0) return null;

        return targetSheet.FirstOrDefault();

    }

    else if (sheetIndex > 0 && sheetIndex + 1 <= excelWorksheets.Count())

    {

        return excelWorksheets[sheetIndex + 1];

    }

    else

    {

        return excelWorksheets.FirstOrDefault();

    }

}

private Dictionary<int, PropertyInfo> GetColumnIndexDicFromExcelHeader(ExcelWorksheet sheet, List<long> excluedeColumns)

{

    if (_displayAttrDic == null)

    {

        //获取 Dictionary<excel column Header text,DisplayAttribute>

        _displayAttrDic = GetDisplayDicFromType(typeof(T));

    }

    Dictionary<int, PropertyInfo> displayOrderDic = new Dictionary<int, PropertyInfo>();

    if (sheet == nullreturn displayOrderDic;

    if(_displayAttrDic == null|| _displayAttrDic.Count == 0)

    {

        _logger.Warn($"no _displayAttrDic can get .");

        return displayOrderDic;

    }

    //获取 Dictionary<column index,PropertyInfo of class T>

    var query1 = (from cell in sheet.Cells[1, 1, 1, sheet.Dimension.Columns] where !excluedeColumns.Contains(cell.Start.Column) select cell);

    foreach (var cell in query1)

    {

        var columnName = cell.Value.ToString().ToLower().Trim();

        if (_displayAttrDic.ContainsKey(columnName))

        {

            var propertyInfo = _displayAttrDic[columnName];

            displayOrderDic.Add(cell.Start.Column, propertyInfo);

        }

    }

    if (displayOrderDic == null || displayOrderDic.Count() == 0)

    {

        _logger.Warn($"no ColumnIndexDic can get from ExcelHeader. sheet:{sheet.Name},_displayAttrDic got no data");

    }

    return displayOrderDic;

}

private Dictionary<string,PropertyInfo> GetDisplayDicFromType(Type typeOfObject)

{

    var pds = typeOfObject.GetProperties();

    if (pds == nullreturn null;

    //DisplayAttribute 中的Name==excel column Header

    var propertyDic = pds.ToLookup(p=> {

        var attr = p.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;

        if (attr == nullreturn "";

        return attr.Name.ToLower().Trim();

    }).ToDictionary(kp => kp.Key, kp=> kp.FirstOrDefault());

    if(propertyDic==null|| propertyDic.Count() == 0)

    {

        _logger.Warn($"no DisplayDic can get from class Type:{typeOfObject.FullName} ");

    }

    return propertyDic;

}

private List<T> GetDatesFromContent(ExcelWorksheet sheet, Dictionary<int, PropertyInfo> columnIndexDic, List<long> excluedeColumns)
{
    List<T> result = new List<T>();
    //fill list form excel
    Dictionary<string, Dictionary<string, object>> enumDic = new Dictionary<string, Dictionary<string, object>>();
    var query2 = (from cell in sheet.Cells[2, 1, sheet.Dimension.Rows, sheet.Dimension.Columns] where !excluedeColumns.Contains(cell.Start.Column) select cell);
    T temp = default(T);
    foreach (var cell in query2)
    {
        if (cell.Start.Column == 1)
        {
            if (temp != null) result.Add(temp);
            temp = (T)Activator.CreateInstance(typeof(T));
        }
        if (cell.Value == null || string.IsNullOrWhiteSpace(cell.Value.ToString())) continue;
        SetValueAccordingEachCell(cell, temp, columnIndexDic, ref enumDic);
    }
    if (temp != null) result.Add(temp);
    return result;
}
 
//according cell value to set T's property value
private void SetValueAccordingEachCell(ExcelRangeBase cell, T temp, Dictionary<int, PropertyInfo> columnIndexDic, ref Dictionary<string, Dictionary<string, object>> enumDic)
{
    try
    {
        var columnIndex = cell.Start.Column;
        if (columnIndexDic == null || columnIndexDic.Count() == 0)
        {
            _logger.Warn($"no column Index can get from cell(address:{cell.Start.Address} ,value:{cell.Value})");
            return;
        }
        if (!columnIndexDic.ContainsKey(columnIndex))
        {
            _logger.Warn($"no column Index can get from cell(address:{cell.Start.Address} ,value:{cell.Value}),columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}");
            return;
        }
        var propertyInfo = columnIndexDic[columnIndex];
        Type propertyType = propertyInfo.PropertyType;
        if (propertyType.IsEnum)
        {
            Dictionary<string, object> enumDicTemp;
            if (enumDic.ContainsKey(propertyType.FullName))
            {
                enumDicTemp = enumDic[propertyType.FullName];
            }
            else
            {
                enumDicTemp = GetEnumDicFromType(propertyType);
                enumDic.Add(propertyType.FullName, enumDicTemp);
            }
 
            object enumValue = null;
            if (enumDicTemp != null)
            {
                if (enumDicTemp.ContainsKey(cell.Value.ToString()))
                {
                    enumValue = enumDicTemp[cell.Value.ToString()];
                }
                else
                {
                    _logger.Warn($"no enum value can get from enum dictionary:{JsonConvert.SerializeObject(enumDicTemp.Keys)} , enum Type:{propertyType.FullName},cell (address:{cell.Start.Address},value:{cell.Value.ToString()})");
                }
            }
            else
            {
                _logger.Warn($"no enum dictionary can get from enum Type:{propertyType.FullName} ");
            }
 
            if (enumValue != null)
            {
                propertyInfo.SetValue(temp, enumValue);
            }
            else
            {
                _logger.Warn($"no enum value can get for cell:{cell.Value} ");
            }
            return;
        }
        if (propertyType == typeof(decimal))
        {
            string cellV = cell.Value.ToString();
            decimal multiply = 1;
            if (cellV.Contains("%"))
            {
                multiply = 100;
                cellV = cellV.Substring(0, cellV.IndexOf("%") + 1);
            }
            decimal tempV;
            bool convertR = decimal.TryParse(cellV, out tempV);
            if (convertR)
            {
                propertyInfo.SetValue(temp, tempV * multiply);
            }
            else
            {
                _logger.Warn($"no decimal value can get for cell:(address:{cell.Address},value:{cell.Value})");
            }
            return;
        }
        if (propertyType == typeof(int))
        {
            propertyInfo.SetValue(temp, Convert.ToInt32(cell.Value));
            return;
        }
        if (propertyType == typeof(long))
        {
            propertyInfo.SetValue(temp, Convert.ToInt64(cell.Value));
            return;
        }
        if (propertyType == typeof(DateTime))
        {
            propertyInfo.SetValue(temp, Convert.ToDateTime(cell.Value));
            return;
        }
        if (propertyType == typeof(string))
        {
            propertyInfo.SetValue(temp, cell.Value.ToString());
            return;
        }
        propertyInfo.SetValue(temp, cell.Value.ToString());
        return;
    }
    catch(Exception ex)
    {
        _logger.Error($"no property value can set from cell:(address:{cell.Address},value:{cell.Value})");
        throw ex;
    }
}
 
// get Dictionary<enumn's display name==excel cell value,emumn value>
private Dictionary<string, object> GetEnumDicFromType(Type propertyType)
{
    var result = new Dictionary<string, object>();
    if (propertyType.IsEnum)
    {
        var enumValues = propertyType.GetEnumValues();
        foreach (var value in enumValues)
        {
            MemberInfo memberInfo =
                propertyType.GetMember(value.ToString()).First();
            var descriptionAttribute =
                memberInfo.GetCustomAttribute<DisplayAttribute>();
            if (descriptionAttribute != null)
            {
                result.Add(descriptionAttribute.Name, value);
            }
            else
            {
                var enumString = Enum.GetName(propertyType, value);
                result.Add(enumString, value);
            }
        }
        if (result == null || result.Count() == 0)
        {
            _logger.Warn($"no EnumDic can get from enum Type:{propertyType.FullName} ");
        }
    }
    return result;
}

相关辅助类:

enum class

public enum AdvertiseType:Int32

{

    /// <summary>

    /// Search

    /// </summary>

    [Display(Name = "Search")]

    Search = 1,

    /// <summary>

    /// Display

    /// </summary>

    [Display(Name = "Display")]

    Display = 2,

}

T class:

public class FinancialBillEntity

{

    [Display(Name = "类型")]

    public BussinessType AdvertiseType{ getset; }

   

    [Display(Name = "平台2343")]

    public string AdvertisePlantform { getset; }

    

    [Display(Name = "签约12312")]

    public string PlantformSignEntity { getset; }

}

应用:

//register interface

services.RegisterServiceR<ExcelReadServiceAccordingDisplayAttr<FinancialBillEntity>,IExcelReadService<FinancialBillEntity>>(lifeStyle);

//get interface instance

var excelWriteService= services.GetInstance<IExcelWriteService<FinancialBillEntity>>();

//execute interface method

bool result=_excelWriteService.WriteData(financeBills,cmdOptions.OutputFinanceBillExcelPath,cmdOptions.OutputFinanceBillSheetName);

猜你喜欢

转载自blog.csdn.net/BUBsky/article/details/88786424