基于NPOI的Excel数据导入
从Excel导入数据最令人头疼的是数据格式的兼容性,特别是日期类型的兼容性。为了能够无脑导入日期,折腾了一天的NPOI。在经过测试确实可以导入任意格式的合法日期后,写下这篇小文,与大家共享。完整代码请移步:https://github.com/xuanbg/Utility
2016-11-13 04:06 修正一个bug。由try DateCellValue改为判断列数据类型,如类型为DateTiime返回DateCellValue,否则返回NumericCellValue或StringCellValue。
概述:
这个帮助类是一个泛型类,泛型参数对应的实体类还起到模板的作用。如果你的Excel文件使用与实体类不同的列标题的话,可以通过给属性加上Alias特性,将列标题和属性进行对应。例如:
Excel格式如图:

实体类:
using System;
using Insight.Utils.Common; namespace Insight.WS.Server.Common.Entity
{
public class Logistics
{
[Alias("订单号")]
public string OrderCode { get; set; } [Alias("物流公司")]
public string Service { get; set; } [Alias("物流单号")]
public string Number { get; set; } [Alias("发货时间")]
public DateTime DeliveryTime { get; set; }
}
}
返回的Json:
[
{
"OrderCode": "201611S1200324",
"Service": "顺丰",
"Number": "33012231F54351",
"DeliveryTime": "2016-11-10T11:02:44"
},
{
"OrderCode": "",
"Service": "顺丰",
"Number": "33012231F54352",
"DeliveryTime": "2016-11-12T09:02:44"
},
{
"OrderCode": "",
"Service": "EMS",
"Number": "33012231F54353",
"DeliveryTime": "2016-11-12T09:02:44"
}
]
1、类主体,负责根据传入的文件路径读取数据,并调用其他私有方法对数据进行处理。最后转换成List<T>并序列化成Json返回。
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using Insight.Utils.Entity;
using NPOI.SS.UserModel; namespace Insight.Utils.Common
{
public class NpoiHelper<T> where T : new()
{
private readonly Result _Result = new Result(); /// <summary>
/// 导入Excel文件
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="index">Sheet索引</param>
/// <returns>Result</returns>
public Result Import(string path, int index = )
{
if (!File.Exists(path))
{
_Result.FileNotExists();
return _Result;
} IWorkbook book;
using (var file = new FileStream(path, FileMode.Open, FileAccess.Read))
{
book = WorkbookFactory.Create(file);
} if (index >= book.NumberOfSheets)
{
_Result.SheetNotExists();
return _Result;
} var sheet = book.GetSheetAt(index);
var table = GetSheetData(sheet);
var list = Util.ConvertToList<T>(table);
_Result.Success(list);
return _Result;
}
}
}
2、GetSheetData方法,负责将Sheet中的数据读取到DataTable。这里通过实体类属性的特性值作为列名,属性类型作为列数据类型来初始化DataTable。当然,首行是例外,因为首行是列标题而非数据。
/// <summary>
/// 读取Sheet中的数据到DataTable
/// </summary>
/// <param name="sheet">当前数据表</param>
/// <returns>DataTable</returns>
private DataTable GetSheetData(ISheet sheet)
{
var table = InitTable(sheet);
if (table == null) return null; var rows = sheet.GetEnumerator();
while (rows.MoveNext())
{
var row = (IRow) rows.Current;
if (row.RowNum == ) continue; var dr = table.NewRow();
for (var i = ; i < table.Columns.Count; i++)
{
try
{
var type = table.Columns[i].DataType;
dr[i] = GetCellData(row.GetCell(i), type);
}
catch (Exception)
{
dr[i] = DBNull.Value;
} }
table.Rows.Add(dr);
} return table;
}
初始化DataTable的方法:
/// <summary>
/// 初始化DataTable
/// </summary>
/// <param name="sheet">当前数据表</param>
/// <returns>DataTable</returns>
private DataTable InitTable(ISheet sheet)
{
var title = sheet.GetRow();
if (title == null)
{
_Result.NoRowsRead();
return null;
} try
{
var dict = GetDictionary();
var table = new DataTable();
foreach (var cell in title.Cells)
{
var col_name = cell.StringCellValue;
var col_type = dict[col_name];
table.Columns.Add(cell.StringCellValue, col_type);
} return table;
}
catch
{
_Result.IncorrectExcelFormat();
return null;
}
}
生成模板字典的方法:
/// <summary>
/// 获取指定类型的属性名称/类型字典
/// </summary>
/// <returns>Dictionary</returns>
private Dictionary<string, Type> GetDictionary()
{
var dict = new Dictionary<string, Type>();
var propertys = typeof(T).GetProperties();
foreach (var p in propertys)
{
string name;
var attributes = p.GetCustomAttributes(typeof(AliasAttribute), false);
if (attributes.Length > )
{
var type = (AliasAttribute)attributes[];
name = type.Alias;
}
else
{
name = p.Name;
} dict.Add(name, p.PropertyType);
} return dict;
}
3、重点来了!
因为日期/时间在Excel中可能被表示为文本格式或日期格式(其实是Numeric类型),所以在CellType为String/Numeric的时候,如果列数据类型为DateTime,则取cell的DateCellValue,否则取cell的StringCellValue/NumericCellValue就好了。
这样,无论日期是文本或日期格式,都可以完美获取。
/// <summary>
/// 读Excel单元格的数据
/// </summary>
/// <param name="cell">Excel单元格</param>
/// <param name="type">列数据类型</param>
/// <returns>object 单元格数据</returns>
private object GetCellData(ICell cell, Type type)
{
switch (cell.CellType)
{
case CellType.Numeric:
if (type == typeof(DateTime)) return cell.DateCellValue; return cell.NumericCellValue; case CellType.String:
if (type == typeof(DateTime)) return cell.DateCellValue; return cell.StringCellValue; case CellType.Boolean:
return cell.BooleanCellValue; case CellType.Unknown:
case CellType.Formula:
case CellType.Blank:
case CellType.Error:
return null;
default:
return null;
}
}
4、DataTable转成List<T>的方法:
/// <summary>
/// 将DataTable转为List
/// </summary>
/// <param name="table">DataTable</param>
/// <returns>List</returns>
public static List<T> ConvertToList<T>(DataTable table) where T: new()
{
var list = new List<T>();
var propertys = typeof(T).GetProperties();
foreach (DataRow row in table.Rows)
{
var obj = new T();
foreach (var p in propertys)
{
string name;
var attributes = p.GetCustomAttributes(typeof(AliasAttribute), false);
if (attributes.Length > )
{
var type = (AliasAttribute) attributes[];
name = type.Alias;
}
else
{
name = p.Name;
} if (table.Columns.Contains(name))
{
if (!p.CanWrite) continue; var value = row[name];
if (value == DBNull.Value) value = null; p.SetValue(obj, value, null);
}
}
list.Add(obj);
}
return list;
}
自定义特性:
using System; namespace Insight.Utils.Common
{
[AttributeUsage(AttributeTargets.Property)]
public class AliasAttribute : Attribute
{
/// <summary>
/// 属性别名
/// </summary>
public string Alias { get; } /// <summary>
/// 构造方法
/// </summary>
/// <param name="alias">别名</param>
public AliasAttribute(string alias)
{
Alias = alias;
}
}
}
请大家对此多发表意见和建议,谢谢。
基于NPOI的Excel数据导入的更多相关文章
- Npoi将excel数据导入到sqlserver数据库
/// <summary> /// 将excel导入到datatable /// </summary> /// <param name="filePath&qu ...
- 基于ElementUI封装Excel数据导入组件
由于前端项目使用的是Vue-cli3.0 + TypeScript的架构,所以该组件也是基于ts语法封装的,组件的完整代码如下: <template> <div id="m ...
- 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续3篇-导出时动态生成多Sheet EXCEL)
ExcelUtility 类库经过我(梦在旅途)近期不断的优化与新增功能,现已基本趋向稳定,功能上也基本可以满足绝大部份的EXCEL导出需求,该类库已在我们公司大型ERP系统全面使用,效果不错,今天应 ...
- 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)
自ExcelUtility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板.结果图,以便大家快速掌握,另外这些示例说 ...
- 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续篇)
上周六我发表的文章<分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility>受到了大家的热烈支持与推荐,再此表示感谢,该ExcelUtility ...
- 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility
1. ExcelUtility功能: 1.将数据导出到EXCEL(支持XLS,XLSX,支持多种类型模板,支持列宽自适应) 类名:ExcelUtility. Export 2.将EXCEL ...
- 效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】) 转
效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中[附源代码下载]) 本文目录: (一)背景 (二)数据库数据导入到Excel的方法比较 ...
- 使用NPOI读取Excel数据到DataTable
如今XML文件的存储格式大行其道,可是也不是适用于全部情况,非常多单位的数据交换还是使用Excel的形式.这就使得我们须要读取Excel内的数据.载入到程序中进行处理.可是如何有效率的读取,如何使程序 ...
- 批量Excel数据导入Oracle数据库
由于一直基于Oracle数据库上做开发,因此常常会需要把大量的Excel数据导入到Oracle数据库中,其实如果从事SqlServer数据库的开发,那么思路也是一样的,本文主要介绍如何导入Excel数 ...
随机推荐
- Angular杂谈系列1-如何在Angular2中使用jQuery及其插件
jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...
- 首个threejs项目-前端填坑指南
第一次使用threejs到实际项目中,开始的时候心情有点小激动,毕竟是第一次嘛,然而做着做着就感受到这玩意水好深,满满的都是坑,填都填不过来.经过老板20天惨无人道的摧残,终于小有成就. 因为第一次搞 ...
- C语言 · 阶乘计算 · 基础练习
问题描述 输入一个正整数n,输出n!的值. 其中n!=1*2*3*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组A来表示一个大整数a,A[0]表 ...
- JavaScript 开发规范
本篇主要介绍JS的命名规范.注释规范以及框架开发的一些问题. 目录 1. 命名规范:介绍变量.函数.常量.构造函数.类的成员等等的命名规范 2. 注释规范:介绍单行注释.多行注释以及函数注释 3. 框 ...
- Word/Excel 在线预览
前言 近日项目中做到一个功能,需要上传附件后能够在线预览.之前也没做过这类似的,于是乎就查找了相关资料,.net实现Office文件预览大概有这几种方式: ① 使用Microsoft的Office组件 ...
- Android数据加密之SHA安全散列算法
前言: 对于SHA安全散列算法,以前没怎么使用过,仅仅是停留在听说过的阶段,今天在看图片缓存框架Glide源码时发现其缓存的Key采用的不是MD5加密算法,而是SHA-256加密算法,这才勾起了我的好 ...
- Python爬虫小白入门(四)PhatomJS+Selenium第一篇
一.前言 在上一篇博文中,我们的爬虫面临着一个问题,在爬取Unsplash网站的时候,由于网站是下拉刷新,并没有分页.所以不能够通过页码获取页面的url来分别发送网络请求.我也尝试了其他方式,比如下拉 ...
- bzoj1723--前缀和(水题)
题目大意: 你难以想象贝茜看到一只妖精在牧场出现时是多么的惊讶.她不是傻瓜,立即猛扑过去,用她那灵活的牛蹄抓住了那只妖精. "你可以许一个愿望,傻大个儿!"妖精说. ...
- Spring异步功能
使用 Spring 的异步功能时,实质是使用的 Servlet3 及以上版本的异步功能. Spring 的异步处理机制需要在 web.xml 中全部的 servlet 和 filter 处配置 < ...
- svn常用命令
1.新建版本库 [root@localhost repos]# mkdir -p project [root@localhost repos]# svnadmin create project [ro ...