分享我基于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  ,如需转载请自行联系原作者

相关文章
|
12天前
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
|
2月前
|
前端开发
实现Excel文件和其他文件导出为压缩包,并导入
实现Excel文件和其他文件导出为压缩包,并导入
37 1
|
2月前
|
数据格式 UED
记录一次NPOI库导出Excel遇到的小问题解决方案
【11月更文挑战第16天】本文记录了使用 NPOI 库导出 Excel 过程中遇到的三个主要问题及其解决方案:单元格数据格式错误、日期格式不正确以及合并单元格边框缺失。通过自定义单元格样式、设置数据格式和手动添加边框,有效解决了这些问题,提升了导出文件的质量和用户体验。
231 3
|
2月前
|
Java API Apache
|
2月前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
99 4
|
3月前
|
JavaScript 前端开发 数据处理
Vue导出el-table表格为Excel文件的两种方式
Vue导出el-table表格为Excel文件的两种方式
146 6
|
1月前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
118 10
|
3月前
|
数据采集 存储 JavaScript
自动化数据处理:使用Selenium与Excel打造的数据爬取管道
本文介绍了一种使用Selenium和Excel结合代理IP技术从WIPO品牌数据库(branddb.wipo.int)自动化爬取专利信息的方法。通过Selenium模拟用户操作,处理JavaScript动态加载页面,利用代理IP避免IP封禁,确保数据爬取稳定性和隐私性。爬取的数据将存储在Excel中,便于后续分析。此外,文章还详细介绍了Selenium的基本设置、代理IP配置及使用技巧,并探讨了未来可能采用的更多防反爬策略,以提升爬虫效率和稳定性。
184 4
|
5月前
|
关系型数据库 MySQL Shell
不通过navicat工具怎么把查询数据导出到excel表中
不通过navicat工具怎么把查询数据导出到excel表中
58 0
|
3月前
|
数据处理 Python
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
这篇文章介绍了如何使用Python读取Excel文件中的数据,处理后将其保存为txt、xlsx和csv格式的文件。
174 3
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档