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 == null) return 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 == null) return 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 == null) return 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 == null) return null;
var propertyDic = pds.ToLookup(p => {
var attr = p.GetCustomAttribute(typeof(RequiredAttribute)) as RequiredAttribute;
if (attr == null) return "";
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 == null) return 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 == null) return 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 == null) return null;
//DisplayAttribute 中的Name==excel column Header
var propertyDic = pds.ToLookup(p=> {
var attr = p.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
if (attr == null) return "";
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{ get; set; }
[Display(Name = "平台2343")]
public string AdvertisePlantform { get; set; }
[Display(Name = "签约12312")]
public string PlantformSignEntity { get; set; }
}
应用:
//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);
EPPlus实战篇——Excel读取的更多相关文章
- EPPlus实战篇——Excel写入
.net core 项目 可以向excel写入任何类型(T)的数据,只要T中的field的[Display(Name = "1233", Description = "# ...
- python基础 实战作业 ---Excel基本读写与数据处理
代码地址如下:http://www.demodashi.com/demo/11650.html 看完本篇需要: 10min 作业练习需要: 0.5h~3h(依练习者对python熟悉程度而定) 看完本 ...
- 二、Redis基本操作——String(实战篇)
小喵万万没想到,上一篇博客,居然已经被阅读600次了!!!让小喵感觉压力颇大.万一有写错的地方,岂不是会误导很多筒子们.所以,恳请大家,如果看到小喵的博客有什么不对的地方,请尽快指正!谢谢! 小喵的唠 ...
- javamail模拟邮箱功能发送电子邮件-基础实战篇(javamail API电子邮件实例)
引言: JavaMail 是一种可选的.能用于读取.编写和发送电子消息的包 JavaMail jar包下载地址:http://java.sun.com/products/javamail/downlo ...
- Systemd 入门教程:实战篇
Systemd 入门教程:实战篇 上一篇文章,介绍了 Systemd 的主要命令,这篇文章主要介绍如何使用 Systemd 来管理我们的服务,以及各项的含义: 一.开机启动 对于那些支持 System ...
- ArcGIS制图表达Representation实战篇4-自由式制图表达
ArcGIS制图表达Representation实战篇4-自由式制图表达 by 李远祥 上一章节关于制图表达的控制点中已经介绍过制图表达的编辑功能,利用制图表达的编辑功能,可以实现一些规则以外的效果. ...
- 持续集成之 Spring Boot 实战篇
本文作者: CODING 用户 - 何健 这次实战篇,我们借助「CODING 持续集成」,实现一个简单的 Spring Boot 项目从编码到最后部署的完整过程.本教程还有 B 站视频版,帮助读者更好 ...
- 洗礼灵魂,修炼python(82)--全栈项目实战篇(10)—— 信用卡+商城项目(模拟京东淘宝)
本次项目相当于对python基础做总结,常用语法,数组类型,函数,文本操作等等 本项目在博客园里其他开发者也做过,我是稍作修改来的,大体没变的 项目需求: 信用卡+商城: A.信用卡(类似白条/花呗) ...
- javamail模拟邮箱功能--邮件回复-中级实战篇【邮件回复方法】(javamail API电子邮件实例)
引言: JavaMai下载地址l jar包:http://java.sun.com/products/javamail/downloads/index.html 此篇是紧随上篇文章而封装出来的,阅读本 ...
随机推荐
- mysql批量插入,批量更新
进行批量操作的时候,一定要事先判断数组非空 <insert id="batchInsert"parameterType="java.util.List"& ...
- 【Hbase学习之四】Hbase表设计案例
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop-2.6.5 hbase-0.98.12.1-h ...
- loadRunner手动关联, web_reg_save_param_regexp()函数正则匹配字符,赋值给变量
loadRunner写脚本实现登录机票网站,手动关联,获取页面源码中特定字符 手动关联,就是通过函数获取某个步骤生成的字符,赋值给一个变量,这个变量可以作为接下来某个步骤的输入, 以便这个脚本能够在存 ...
- VPS采用的几种常见技术(OVZ、Xen、KVM)介绍与对比
很多人看到同样配置的VPS价格相差很大,甚是不理解,其实VPS使用的虚拟技术种类有很多,如OpenVZ.Xen.KVM.Xen和HVM与PV. 在+XEN中pv是半虚拟化,hvm是全虚拟化,pv只能用 ...
- TensorFire:WEB端的高性能神经网络框架
TensorFire:WEB端的高性能神经网络框架 摘要: 近日,一种专门用于在网页内执行神经网络算法的JavaScript库——TensorFire引起了人们的关注,这种JavaScript库在浏览 ...
- python的类和对象
一.面向对象和面向过程 1.1面向过程的特点 优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可. 缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身. 1.2面 ...
- python-selenium,关于页面滑动的操作
//移动到元素element对象的“顶端”与当前窗口的“顶部”对齐 ((JavascriptExecutor) driver).executeScript("arguments[0].scr ...
- K8S学习笔记之CentOS7集群使用Chrony实现时间同步
0x00 概述 容器集群对时间同步要求高,实际使用环境中必须确保集群中所有系统时间保持一致,openstack官方也推荐使用chrony代替ntp做时间同步. Chrony是一个开源的自由软件,像Ce ...
- Golang利用select和普通函数分别实现斐波那契数列
//斐波那契数列 //1 1 2 3 5 8 //观察规律 //第一轮:前两个数是1,1,相加等于2 //第二轮:第二个数和第三个数是1,2,相加等于3 //第三轮:第三个数和第四个数是2,3,相加等 ...
- fjwc2019 D2T3 排序(堆)
#183. 「2019冬令营提高组」排序 贴一段ppt 考虑模拟出这个算法进行k轮(即外层的i循环到k)时的序列,之后再暴力模拟零散的步. 考虑这个算法在01序列上的表现,k轮后实际上就是将最开始的不 ...