ExcelUtility 类库经过我(梦在旅途)近期不断的优化与新增功能,现已基本趋向稳定,功能上也基本可以满足绝大部份的EXCEL导出需求,该类库已在我们公司大型ERP系统全面使用,效果不错,今天应用户的特殊需求,我又新增了一个功能,导出时动态生成多Sheet EXCEL。

新增方法一:由GetFormatterContainer Func委托导出基于EXCEL模板的多Sheet文件,方法定义如下:

  1. /// <summary>
  2. /// 由GetFormatterContainer Func委托导出基于EXCEL模板的多工作薄文件
  3. /// </summary>
  4. /// <typeparam name="T">数据源可枚举项类型</typeparam>
  5. /// <param name="templatePath">模板路径</param>
  6. /// <param name="sheetName">模板中使用的工作薄名称</param>
  7. /// <param name="dataSource">数据源</param>
  8. /// <param name="getFormatterContainer">生成模板数据格式化容器(SheetFormatterContainer)委托,在委托方法中实现模板的格式化过程</param>
  9. /// <param name="sheetSize">每个工作薄显示的数据记录数</param>
  10. /// <param name="filePath">导出路径,可选</param>
  11. /// <returns></returns>
  12. public static string ToExcelWithTemplate<T>(string templatePath, string sheetName, IEnumerable<T> dataSource, Func<IEnumerable<T>, SheetFormatterContainer> getFormatterContainer, int sheetSize, string filePath = null)
  13. {
  14.  
  15. if (!File.Exists(templatePath))
  16. {
  17. throw new FileNotFoundException(templatePath + "文件不存在!");
  18. }
  19.  
  20. bool isCompatible = Common.GetIsCompatible(templatePath);
  21.  
  22. if (string.IsNullOrEmpty(filePath))
  23. {
  24. filePath = Common.GetSaveFilePath(isCompatible);
  25. }
  26. else if (isCompatible && !Path.GetExtension(filePath).Equals(".xls", StringComparison.OrdinalIgnoreCase))
  27. {
  28. throw new ArgumentException("当模板采用兼容模式时(低版本格式,如:xls,xlt),则指定的导出文件格式必需为xls。");
  29. }
  30.  
  31. if (string.IsNullOrEmpty(filePath)) return null;
  32.  
  33. int sheetCount = 0;
  34. var formatterContainers = new Dictionary<string, SheetFormatterContainer>();
  35. IEnumerable<T> data = null;
  36. while ((data = dataSource.Take(sheetSize)).Count() > 0)
  37. {
  38. var sheetFormatterContainer = getFormatterContainer(data);
  39. sheetCount++;
  40. if (sheetCount == 1)
  41. {
  42. formatterContainers.Add(sheetName, sheetFormatterContainer);
  43. }
  44. else
  45. {
  46. formatterContainers.Add(sheetName + sheetCount.ToString(), sheetFormatterContainer);
  47. }
  48. dataSource = dataSource.Skip(sheetSize);
  49. }
  50. string temp_templatePath = null;
  51. try
  52. {
  53. temp_templatePath = Common.CreateTempFileByTemplate(templatePath, sheetName, sheetCount);
  54. filePath = ToExcelWithTemplate(temp_templatePath, formatterContainers, filePath);
  55. }
  56. finally
  57. {
  58. if (!string.IsNullOrEmpty(temp_templatePath) && File.Exists(temp_templatePath))
  59. {
  60. File.Delete(temp_templatePath);
  61. }
  62. string temp_templateConfigFilePath = Path.ChangeExtension(temp_templatePath, ".xml");
  63. if (File.Exists(temp_templateConfigFilePath))
  64. {
  65. File.Delete(temp_templateConfigFilePath);
  66. }
  67. }
  68.  
  69. return filePath;
  70. }

  

简要说明上述方法实现原理步骤:

1.指定模板路径、初始工作薄名称、导出的数据源、每个工作薄显示的记录数、封装生成模板数据格式化容器(SheetFormatterContainer)委托,在委托方法中实现模板的格式化过程;

2.依据每个工作薄显示的记录数,循环拆分数据源,并计算出需要的工作薄总数以及生成模板数据格式化容器字典(Key:Sheet名称,Value:模板数据格式化容器对象);

3.生成2中计算的所需的工作薄的临时模板文件(存放在系统的本地临时目录:Temp)

4.调用ToExcelWithTemplate的其它重载方法(基于模板+多sheet生成EXCEL方法)来完成EXCEL的导出;

5.无论最终导出成功与否,将删除临时模板及临时模板配置文件;

测试示例代码如下:

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

测试结果如下:

1.生成的临时模板及模板配置文件:

2.导出的EXCE结果如下:

3.临时模板及模板配置文件已被清除。

新增方法二:增加由DataTable导出多Sheet Excel方法(准确的说是修改ToExcel方法,增加一个sheetSize参数),方法定义如下:

  1. /// <summary>
  2. /// 由DataTable导出Excel
  3. /// </summary>
  4. /// <param name="sourceTable">要导出数据的DataTable</param>
  5. /// <param name="sheetName">工作薄名称,可选</param>
  6. /// <param name="filePath">导出路径,可选</param>
  7. /// <param name="colNames">需要导出的列名,可选</param>
  8. /// <param name="colAliasNames">导出的列名重命名,可选</param>
  9. /// <param name="colDataFormats">列格式化集合,可选</param>
  10. /// <param name="sheetSize">指定每个工作薄显示的记录数,可选(不指定或指定小于0,则表示只生成一个工作薄)</param>
  11. /// <returns></returns>
  12. public static string ToExcel(DataTable sourceTable, string sheetName = "result", string filePath = null, string[] colNames = null, IDictionary<string, string> colAliasNames = null, IDictionary<string, string> colDataFormats = null, int sheetSize = 0)
  13. {
  14. if (sourceTable.Rows.Count <= 0) return null;
  15.  
  16. if (string.IsNullOrEmpty(filePath))
  17. {
  18. filePath = Common.GetSaveFilePath();
  19. }
  20.  
  21. if (string.IsNullOrEmpty(filePath)) return null;
  22.  
  23. bool isCompatible = Common.GetIsCompatible(filePath);
  24.  
  25. IWorkbook workbook = Common.CreateWorkbook(isCompatible);
  26. ICellStyle headerCellStyle = Common.GetCellStyle(workbook, true);
  27. //ICellStyle cellStyle = Common.GetCellStyle(workbook);
  28.  
  29. if (colNames == null || colNames.Length <= 0)
  30. {
  31. colNames = sourceTable.Columns.Cast<DataColumn>().OrderBy(c => c.Ordinal).Select(c => c.ColumnName).ToArray();
  32. }
  33.  
  34. IEnumerable<DataRow> batchDataRows, dataRows = sourceTable.Rows.Cast<DataRow>();
  35. int sheetCount = 0;
  36. if (sheetSize <= 0)
  37. {
  38. sheetSize = sourceTable.Rows.Count;
  39. }
  40. while ((batchDataRows = dataRows.Take(sheetSize)).Count() > 0)
  41. {
  42.  
  43. Dictionary<int, ICellStyle> colStyles = new Dictionary<int, ICellStyle>();
  44.  
  45. ISheet sheet = workbook.CreateSheet(sheetName + (++sheetCount).ToString());
  46. IRow headerRow = sheet.CreateRow(0);
  47.  
  48. // handling header.
  49. for (int i = 0; i < colNames.Length; i++)
  50. {
  51. ICell headerCell = headerRow.CreateCell(i);
  52. if (colAliasNames != null && colAliasNames.ContainsKey(colNames[i]))
  53. {
  54. headerCell.SetCellValue(colAliasNames[colNames[i]]);
  55. }
  56. else
  57. {
  58. headerCell.SetCellValue(colNames[i]);
  59. }
  60. headerCell.CellStyle = headerCellStyle;
  61. sheet.AutoSizeColumn(headerCell.ColumnIndex);
  62. if (colDataFormats != null && colDataFormats.ContainsKey(colNames[i]))
  63. {
  64. colStyles[headerCell.ColumnIndex] = Common.GetCellStyleWithDataFormat(workbook, colDataFormats[colNames[i]]);
  65. }
  66. else
  67. {
  68. colStyles[headerCell.ColumnIndex] = Common.GetCellStyle(workbook);
  69. }
  70. }
  71.  
  72. // handling value.
  73. int rowIndex = 1;
  74.  
  75. foreach (DataRow row in batchDataRows)
  76. {
  77. IRow dataRow = sheet.CreateRow(rowIndex);
  78.  
  79. for (int i = 0; i < colNames.Length; i++)
  80. {
  81. ICell cell = dataRow.CreateCell(i);
  82. //cell.SetCellValue((row[colNames[i]] ?? "").ToString());
  83. //cell.CellStyle = cellStyle;
  84. Common.SetCellValue(cell, (row[colNames[i]] ?? "").ToString(), sourceTable.Columns[colNames[i]].DataType, colStyles);
  85. Common.ReSizeColumnWidth(sheet, cell);
  86. }
  87.  
  88. rowIndex++;
  89. }
  90. sheet.ForceFormulaRecalculation = true;
  91.  
  92. dataRows = dataRows.Skip(sheetSize);
  93. }
  94.  
  95. FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
  96. workbook.Write(fs);
  97. fs.Dispose();
  98. workbook = null;
  99.  
  100. return filePath;
  101. }

修改代码部份说明:增加依据指定的每个工作薄显示的记录数(sheetSize)来循环拆分数据源及创建多个工作薄;

测试示例代码如下:

  1. /// <summary>
  2. /// 测试方法:测试将DataTable导出到多工作薄EXCEL
  3. /// </summary>
  4. [TestMethod]
  5. public void TestExportToExcelByDataTable8()
  6. {
  7. DataTable dt = GetDataTable();
  8. string excelPath = ExcelUtility.Export.ToExcel(dt, "sheet", sheetSize: 10);//指定每个工作薄显示的记录数
  9.  
  10. Assert.IsTrue(File.Exists(excelPath));
  11. }

导出的EXCE结果如下:

源代码同步更新至开源社区的GIT目录中,具体地址请看我该系列之前的文章有列出,在此就不再说明。

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility 其它相关文章链接:

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续3篇-导出时动态生成多Sheet EXCEL)的更多相关文章

  1. 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)

    自ExcelUtility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板.结果图,以便大家快速掌握,另外这些示例说 ...

  2. 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续篇)

    上周六我发表的文章<分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility>受到了大家的热烈支持与推荐,再此表示感谢,该ExcelUtility ...

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

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

  4. 【EXCEL终极总结分享】基于NPOI扩展封装的简易操作工具类库(简单灵活易用,支持导出、导入、上传等常见操作)

    对于EXCEL的导入.导出,我之前已分享过多次,比如: 第一种方案:<我写的一个ExcelHelper通用类,可用于读取或生成数据>这个主要是利用把EXCEL当成一个DB来进行获取数据,导 ...

  5. 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据

    1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...

  6. NPOI+ExcelReport

    分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)   自ExcelUtility类推出以来,经过项目中的实际使用与不断完 ...

  7. 基于NPOI导出和导入Excel

    概述 NPOI,顾名思义,就是POI的.NET版本.NPOI就是用.NET语言编写的一套数据导出Excel的开源项目,支持XML.xls.xlsx.ppt等格式..NET不仅实现Excel导出还可以实 ...

  8. 基于NPOI的报表引擎——ExcelReport

    前言 其实现在说ExcelReport是报表引擎还为时尚早,但该组件我既然要决心维护下去,这便算是初衷吧! 1.现在,ExcelReport能为你做什么呢? 如果,你有导出数据到Excel的需求,Ex ...

  9. 基于NPOI导出Excel

    在上一篇文章[关于大数据的查询与导出]中,提到了使用NPOI组件导出Excel,本想上次一起分享给大家,无奈最近比较忙,今天抽空整理了下,分享出来. 预置填充模板,并且需要支持公式计算; 可导入图片; ...

随机推荐

  1. 实践.Net Core在Linux环境下的第一个Hello World

    基础环境和相关软件准备 1.CentOS7.1 64位系统(或者其他CentOS版本的64位系统) 2.WinSCP软件(主要是方便管理和编辑Linux系统的文件) 3.XShell软件(Window ...

  2. 一个App完成入门篇(六)- 完成通讯录页面

    第五章和第六章间隔时间有点长,对不起大家了.下面继续. 本节教程将要教会大家如何加载本地通讯录. 导入项目 导入通讯录 自定义js模块 发送和订阅page消息 将要学习的demo效果图如下所示 1. ...

  3. MySQL 存储过程

    MySQL 存储过程 存储过程是通过给定的语法格式编写自定义的数据库API,类似于给数据库编写可执行函数. 简介 存储过程是一组为了完成特定功能的SQL语句集合,是经过编译后存储在数据库中. 存储过程 ...

  4. ASP.NET MVC 路由(五)

    ASP.NET MVC 路由(五) 前言 前面的篇幅讲解了MVC中的路由系统,只是大概的一个实现流程,让大家更清晰路由系统在MVC中所做的以及所在的位置,通过模糊的概念描述.思维导图没法让您看到路由的 ...

  5. ORA-12899: value too large for column (actual: 27, maximum: 20)

    导入数据时报错以下错误,这是因为原来的数据库是GBK的,每个汉字两个字节,但新数据库是UTF-8的,每个汉字是三个字节,导致超过长度了. ORA-12899: value too large for ...

  6. SQL Server 的 Statistics 簡介

    當你要清空「資料表(table)」,或倒入大量「資料(data;record)」,或公司「資料庫(database)」改用新版本要資料大搬家…等情形,不只是要重建「索引(index)」,還應要重建或更 ...

  7. Jmeter 使用Jmeter与Badboy进行压力测试

    1. 介绍 Badboy是一个录制请求的工具,这里用它来生成文件给JMeter用. JMeter是一个用java写的开源的性能测试工具,用于模拟在服务器.网络或者其他对象上附加高负载以测试他们提供服务 ...

  8. 轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)

    轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)(国家级奖项获奖作品升级版,四版累计印刷27次发行量超10万册的轻量级Jav ...

  9. 搭建LNAMP环境(三)- 源码安装Apache2.4

    上一篇:搭建LNAMP环境(二)- 源码安装Nginx1.10 1.yum安装编译apache需要的包(如果已经安装,可跳过此步骤) yum -y install pcre pcre-devel zl ...

  10. 前端:圆图头像制作--border-radius : 100%

    异常处理汇总-前端系列 http://www.cnblogs.com/dunitian/p/4523015.html border-radius : 100% border-radius: 6px; ...