分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility

简介:

1. ExcelUtility功能:
 1.将数据导出到EXCEL(支持XLS,XLSX,支持多种类型模板,支持列宽自适应)
 类名:ExcelUtility. Export


 2.将EXCEL数据导入到数据对象中(DataTable、Dataset,支持XLS,XLSX)
 类名:ExcelUtility. Import

  类库项目文件结构如下图示:

  


 2. ExcelUtility依赖组件:
 1.NPOI 操作EXCEL核心类库
 2.NPOI.Extend NPOI扩展功能
 3. ExcelReport 基于NPOI的二次扩展,实现模板化导出功能
 4. System.Windows.Forms 导出或导入时,弹出文件选择对话框(如果用在WEB中可以不需要,但我这里以CS端为主)

3.使用环境准备:

  1.通过NUGet引用NPOI包、ExcelReport 包;(ExcelReport 存在BUG,可能需要用我项目中修复过后的DLL)

  2.引用ExcelUtility类库;

4.具体使用方法介绍(示例代码,全部为测试方法):

导出方法测试:

1
2
3
4
5
6
7
8
9
10
/// <summary>
         /// 测试方法:测试将DataTable导出到EXCEL,无模板
         /// </summary>
         [TestMethod]
         public  void  TestExportToExcelByDataTable()
         {
             DataTable dt = GetDataTable();
             string  excelPath = ExcelUtility.Export.ToExcel(dt,  "导出结果" );
             Assert.IsTrue(File.Exists(excelPath));
         }

结果如下图示:

 

1
2
3
4
5
6
7
8
9
10
11
/// <summary>
/// 测试方法:测试将DataTable导出到EXCEL,无模板,且指定导出的列名
/// </summary>
[TestMethod]
public  void  TestExportToExcelByDataTable2()
{
     DataTable dt = GetDataTable();
     string [] expColNames = {  "Col1" "Col2" "Col3" "Col4" "Col5"  };
     string  excelPath = ExcelUtility.Export.ToExcel(dt,  "导出结果" null , expColNames);
     Assert.IsTrue(File.Exists(excelPath));
}

结果如下图示:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
       /// 测试方法:测试将DataTable导出到EXCEL,无模板,且指定导出的列名,以及导出列名的重命名
       /// </summary>
       [TestMethod]
       public  void  TestExportToExcelByDataTable3()
       {
           DataTable dt = GetDataTable();
           string [] expColNames = {  "Col1" "Col2" "Col3" "Col4" "Col5"  };
           Dictionary< string string > expColAsNames =  new  Dictionary< string string >() {
               { "Col1" , "列一" },
               { "Col2" , "列二" },
               { "Col3" , "列三" },
               { "Col4" , "列四" },
               { "Col5" , "列五" }
           };
           string  excelPath = ExcelUtility.Export.ToExcel(dt,  "导出结果" null , expColNames,expColAsNames);
           Assert.IsTrue(File.Exists(excelPath));
       }

结果如下图示:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
       /// 测试方法:测试将DataTable导出到EXCEL,无模板,且指定导出列名的重命名
       /// </summary>
       [TestMethod]
       public  void  TestExportToExcelByDataTable4()
       {
           DataTable dt = GetDataTable();
           Dictionary< string string > expColAsNames =  new  Dictionary< string string >() {
               { "Col1" , "列一" },
               { "Col5" , "列五" }
           };
           string  excelPath = ExcelUtility.Export.ToExcel(dt,  "导出结果" null null , expColAsNames);
           Assert.IsTrue(File.Exists(excelPath));
       }

结果如下图示:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/// <summary>
/// 测试方法:测试依据模板+DataTable来生成EXCEL
/// </summary>
[TestMethod]
public  void  TestExportToExcelWithTemplateByDataTable()
{
     DataTable dt = GetDataTable(); //获取数据
     string  templateFilePath = AppDomain.CurrentDomain.BaseDirectory +  "/excel.xlsx" //获得EXCEL模板路径
     SheetFormatterContainer<DataRow> formatterContainers =  new  SheetFormatterContainer<DataRow>();  //实例化一个模板数据格式化容器
 
     PartFormatterBuilder partFormatterBuilder =  new  PartFormatterBuilder(); //实例化一个局部元素格式化器
     partFormatterBuilder.AddFormatter( "Title" "IT学员" ); //将模板表格中Title的值设置为跨越IT学员
     formatterContainers.AppendFormatterBuilder(partFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     CellFormatterBuilder cellFormatterBuilder =  new  CellFormatterBuilder(); //实例化一个单元格格式化器
     cellFormatterBuilder.AddFormatter( "rptdate" , DateTime.Today.ToString( "yyyy-MM-dd HH:mm" )); //将模板表格中rptdate的值设置为当前日期
     formatterContainers.AppendFormatterBuilder(cellFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     //实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名
     TableFormatterBuilder<DataRow> tableFormatterBuilder =  new  TableFormatterBuilder<DataRow>(dt.Select(),  "name" );
     tableFormatterBuilder.AddFormatters( new  Dictionary< string , Func<DataRow,  object >>{
         { "name" ,r=>r[ "Col1" ]}, //将模板表格中name对应DataTable中的列Col1
         { "sex" ,r=>r[ "Col2" ]}, //将模板表格中sex对应DataTable中的列Col2
         { "km" ,r=>r[ "Col3" ]}, //将模板表格中km对应DataTable中的列Col3
         { "score" ,r=>r[ "Col4" ]}, //将模板表格中score对应DataTable中的列Col
         { "result" ,r=>r[ "Col5" ]} //将模板表格中result对应DataTable中的列Co5
     });
     formatterContainers.AppendFormatterBuilder(tableFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     string  excelPath = ExcelUtility.Export.ToExcelWithTemplate<DataRow>(templateFilePath,  "table" , formatterContainers);
     Assert.IsTrue(File.Exists(excelPath));
}

模板如下图示:

结果如下图示:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/// <summary>
/// 测试方法:测试依据模板+List来生成EXCEL
/// </summary>
[TestMethod]
public  void  TestExportToExcelWithTemplateByList()
{
     List<Student> studentList = GetStudentList(); //获取数据
     string  templateFilePath = AppDomain.CurrentDomain.BaseDirectory +  "/excel.xlsx" //获得EXCEL模板路径
     SheetFormatterContainer<Student> formatterContainers =  new  SheetFormatterContainer<Student>();  //实例化一个模板数据格式化容器
 
     PartFormatterBuilder partFormatterBuilder =  new  PartFormatterBuilder(); //实例化一个局部元素格式化器
     partFormatterBuilder.AddFormatter( "Title" "IT学员" ); //将模板表格中Title的值设置为跨越IT学员
     formatterContainers.AppendFormatterBuilder(partFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     CellFormatterBuilder cellFormatterBuilder =  new  CellFormatterBuilder(); //实例化一个单元格格式化器
     cellFormatterBuilder.AddFormatter( "rptdate" , DateTime.Today.ToString( "yyyy-MM-dd HH:mm" )); //将模板表格中rptdate的值设置为当前日期
     formatterContainers.AppendFormatterBuilder(cellFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     //实例化一个表格格式化器,studentList本身就是可枚举的无需转换,name表示的模板表格中第一行第一个单元格要填充的数据参数名
     TableFormatterBuilder<Student> tableFormatterBuilder =  new  TableFormatterBuilder<Student>(studentList,  "name" );
     tableFormatterBuilder.AddFormatters( new  Dictionary< string , Func<Student,  object >>{
         { "name" ,r=>r.Name}, //将模板表格中name对应Student对象中的属性Name
         { "sex" ,r=>r.Sex}, //将模板表格中sex对应Student对象中的属性Sex
         { "km" ,r=>r.KM}, //将模板表格中km对应Student对象中的属性KM
         { "score" ,r=>r.Score}, //将模板表格中score对应Student对象中的属性Score
         { "result" ,r=>r.Result} //将模板表格中result对应Student对象中的属性Result
     });
     formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);
 
     string  excelPath = ExcelUtility.Export.ToExcelWithTemplate<Student>(templateFilePath,  "table" , formatterContainers);
     Assert.IsTrue(File.Exists(excelPath));
 
}

结果如下图示:(模板与上面相同)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/// <summary>
/// 测试方法:测试依据模板+DataTable来生成多表格EXCEL(注意:由于NPOI框架限制,目前仅支持模板文件格式为:xls)
/// </summary>
[TestMethod]
public  void  TestExportToRepeaterExcelWithTemplateByDataTable()
{
     DataTable dt = GetDataTable(); //获取数据
     string  templateFilePath = AppDomain.CurrentDomain.BaseDirectory +  "/excel2.xls" //获得EXCEL模板路径
     SheetFormatterContainer<DataRow> formatterContainers =  new  SheetFormatterContainer<DataRow>();  //实例化一个模板数据格式化容器
 
     //实例化一个可重复表格格式化器,dt.Select()是将DataTable转换成DataRow[],rpt_begin表示的模板表格开始位置参数名,rpt_end表示的模板表格结束位置参数名
     RepeaterFormatterBuilder<DataRow> tableFormatterBuilder =  new  RepeaterFormatterBuilder<DataRow>(dt.Select(),  "rpt_begin" "rpt_end" );
     tableFormatterBuilder.AddFormatters( new  Dictionary< string , Func<DataRow,  object >>{
         { "sex" ,r=>r[ "Col2" ]}, //将模板表格中sex对应DataTable中的列Col2
         { "km" ,r=>r[ "Col3" ]}, //将模板表格中km对应DataTable中的列Col3
         { "score" ,r=>r[ "Col4" ]}, //将模板表格中score对应DataTable中的列Col
         { "result" ,r=>r[ "Col5" ]} //将模板表格中result对应DataTable中的列Co5
     });
 
     PartFormatterBuilder<DataRow> partFormatterBuilder2 =  new  PartFormatterBuilder<DataRow>(); //实例化一个可嵌套的局部元素格式化器
     partFormatterBuilder2.AddFormatter( "name" , r => r[ "Col1" ]); //将模板表格中name对应DataTable中的列Col1
     tableFormatterBuilder.AppendFormatterBuilder(partFormatterBuilder2); //添加到可重复表格格式化器中,作为其子格式化器
 
 
     CellFormatterBuilder<DataRow> cellFormatterBuilder =  new  CellFormatterBuilder<DataRow>(); //实例化一个可嵌套的单元格格式化器
     cellFormatterBuilder.AddFormatter( "rptdate" , r => DateTime.Today.ToString( "yyyy-MM-dd HH:mm" )); //将模板表格中rptdate的值设置为当前日期
     tableFormatterBuilder.AppendFormatterBuilder(cellFormatterBuilder); //添加到可重复表格格式化器中,作为其子格式化器
 
     formatterContainers.AppendFormatterBuilder(tableFormatterBuilder); //添加到工作薄格式容器中,注意只有添加进去了才会生效
 
     string  excelPath = ExcelUtility.Export.ToExcelWithTemplate<DataRow>(templateFilePath,  "multtable" , formatterContainers);
     Assert.IsTrue(File.Exists(excelPath));
}

模板如下图示:(注意:该模板仅支持XLS格式文件,XLSX下存在问题)

结果如下图示:

以下是模拟数据来源所定义的方法(配合测试):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private  DataTable GetDataTable()
{
     DataTable dt =  new  DataTable();
     for  ( int  i = 1; i <= 6; i++)
     {
         if  (i == 4)
         {
             dt.Columns.Add( "Col"  + i.ToString(),  typeof ( double ));
         }
         else
         {
             dt.Columns.Add( "Col"  + i.ToString(),  typeof ( string ));
         }
     }
 
     for  ( int  i = 1; i <= 10; i++)
     {
         dt.Rows.Add( "Name"  + i.ToString(), (i % 2) > 0 ?  "男"  "女" "科目"  + i.ToString(), i *  new  Random().Next(1, 5),  "待定" , Guid.NewGuid().ToString( "N" ));
     }
 
     return  dt;
}
 
private  List<Student> GetStudentList()
{
     List<Student> studentList =  new  List<Student>();
     for  ( int  i = 1; i <= 10; i++)
     {
         studentList.Add( new  Student
         {
             Name =  "Name"  + i.ToString(),
             Sex = (i % 2) > 0 ?  "男"  "女" ,
             KM =  "科目"  + i.ToString(),
             Score = i *  new  Random().Next(1, 5),
             Result =  "待定"
         });
     }
     return  studentList;
}
 
class  Student
{
     public  string  Name {  get set ; }
 
     public  string  Sex {  get set ; }
 
     public  string  KM {  get set ; }
 
     public  double  Score {  get set ; }
 
     public  string  Result {  get set ; }
}

导入方法测试:

1
2
3
4
5
6
7
8
9
10
/// <summary>
    /// 测试方法:测试将指定的EXCEL数据导入到DataTable
    /// </summary>
    [TestMethod]
    public  void  TestImportToDataTableFromExcel()
    {
       //null表示由用户选择EXCEL文件路径,data表示要导入的sheet名,0表示数据标题行
       DataTable dt=  ExcelUtility.Import.ToDataTable( null "data" , 0);
       Assert.AreNotEqual(0, dt.Rows.Count);
    }

数据源文件内容如下图示:

 

下面贴出该类库主要源代码:

ExcelUtility.Export类:

  

ExcelUtility.Import类:

Common类根据单元格内容重新设置列宽ReSizeColumnWidth

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 根据单元格内容重新设置列宽
/// </summary>
/// <param name="sheet"></param>
/// <param name="cell"></param>
public  static  void  ReSizeColumnWidth(ISheet sheet, ICell cell)
{
     int  cellLength = (Encoding.Default.GetBytes(cell.ToString()).Length + 5) * 256;
     const  int  maxLength = 255 * 256;
     if  (cellLength > maxLength)
     {
         cellLength = maxLength;
     }
     int  colWidth = sheet.GetColumnWidth(cell.ColumnIndex);
     if  (colWidth < cellLength)
     {
         sheet.SetColumnWidth(cell.ColumnIndex, cellLength);
     }
}

注意这个方法中,列宽自动设置最大宽度为255个字符宽度。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// 创建表格样式
/// </summary>
/// <param name="sheet"></param>
/// <returns></returns>
public  static  ICellStyle GetCellStyle(IWorkbook workbook,  bool  isHeaderRow =  false )
{
     ICellStyle style = workbook.CreateCellStyle();
 
     if  (isHeaderRow)
     {
         style.FillPattern = FillPattern.SolidForeground;
         style.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
         IFont f = workbook.CreateFont();
         f.Boldweight = ( short )FontBoldWeight.Bold;
         style.SetFont(f);
     }
 
     style.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
     style.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
     style.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
     style.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
     return  style;
}

发文时,部份方法代码已经更新了,所以实际效果以GIT项目中的为准。

 该类库源码已分享到该路径中:http://git.oschina.net/zuowj/ExcelUtility    GIT Repository路径:git@git.oschina.net:zuowj/ExcelUtility.git


本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/5113812.html  ,如需转载请自行联系原作者

相关文章
|
17天前
|
SQL 缓存 easyexcel
面试官问10W 行级别数据的 Excel 导入如何10秒处理
面试官问10W 行级别数据的 Excel 导入如何10秒处理
46 0
|
1月前
|
NoSQL 关系型数据库 MySQL
多人同时导出 Excel 干崩服务器?怎样实现一个简单排队导出功能!
业务诉求:考虑到数据库数据日渐增多,导出会有全量数据的导出,多人同时导出可以会对服务性能造成影响,导出涉及到mysql查询的io操作,还涉及文件输入、输出流的io操作,所以对服务器的性能会影响的比较大;结合以上原因,对导出操作进行排队; 刚开始拿到这个需求,第一时间想到就是需要维护一个FIFO先进先出的队列,给定队列一个固定size,在队列里面的人进行排队进行数据导出,导出完成后立马出队列,下一个排队的人进行操作;还考虑到异步,可能还需要建个文件导出表,主要记录文件的导出情况,文件的存放地址,用户根据文件列表情况下载导出文件。
多人同时导出 Excel 干崩服务器?怎样实现一个简单排队导出功能!
|
2月前
|
XML Java 数据格式
使用Freemarker模版导出xls文件使用excel打开提示文件损坏
使用Freemarker模版导出xls文件使用excel打开提示文件损坏
49 0
|
1月前
|
存储 数据处理 数据格式
Python中导入Excel数据:全面解析与实践
Python中导入Excel数据:全面解析与实践
38 0
|
1月前
|
存储 关系型数据库 MySQL
Python导入Excel数据到MySQL数据库
Python导入Excel数据到MySQL数据库
71 0
|
1月前
|
Java easyexcel 应用服务中间件
【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据
【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据
159 0
|
1月前
|
SQL Java easyexcel
【Java】百万数据excel导出功能如何实现
【Java】百万数据excel导出功能如何实现
117 0
|
2月前
|
Java
使用POI导出Excel
使用POI导出Excel
|
2月前
|
前端开发 Java Maven
springboot优雅的实现excel的导出(自适应列宽实现,中文也行),复制可用
springboot优雅的实现excel的导出(自适应列宽实现,中文也行),复制可用
56 0
|
2月前
|
测试技术 数据处理 Python
测试报告导出PDF和excel的方法
测试报告导出PDF和excel的方法