您好,欢迎访问一九零五行业门户网

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

自excelutility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板、结果图,以便大家快速掌握,另外这些示例说明我也已同步到git中,大家可以下载与学习,不足之处,
自excelutility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板、结果图,以便大家快速掌握,另外这些示例说明我也已同步到git中,大家可以下载与学习,不足之处,敬请见谅,谢谢!
一、excelutility类库操作说明(模板导出示例)
1.
/// /// 测试方法:测试依据模板+datatable来生成excel /// [testmethod] public void testexporttoexcelwithtemplatebydatatable() { datatable dt = getdatatable();//获取数据 string templatefilepath = appdomain.currentdomain.basedirectory + /excel.xlsx; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 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 tableformatterbuilder = new tableformatterbuilder(dt.select(), name); tableformatterbuilder.addformatters(new dictionary{ {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中的列col4 {result,r=>r[col5]}//将模板表格中result对应datatable中的列co5 }); formattercontainers.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, table, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板如下:
导出结果如下:
2.
/// /// 测试方法:测试依据模板+list来生成excel /// [testmethod] public void testexporttoexcelwithtemplatebylist() { list studentlist = getstudentlist();//获取数据 string templatefilepath = appdomain.currentdomain.basedirectory + /excel.xlsx; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 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 tableformatterbuilder = new tableformatterbuilder(studentlist, name); tableformatterbuilder.addformatters(new dictionary{ {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(templatefilepath, table, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板同上一个模板
导出结果如下:
3.
/// /// 测试方法:测试依据模板+datatable来生成多表格excel(注意:由于excelreport框架限制,目前仅支持模板文件格式为:xls) /// [testmethod] public void testexporttorepeaterexcelwithtemplatebydatatable() { datatable dt = getdatatable();//获取数据 string templatefilepath = appdomain.currentdomain.basedirectory + /excel2.xls; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 //实例化一个可重复表格格式化器,dt.select()是将datatable转换成datarow[],rpt_begin表示的模板表格开始位置参数名,rpt_end表示的模板表格结束位置参数名 repeaterformatterbuilder tableformatterbuilder = new repeaterformatterbuilder(dt.select(), rpt_begin, rpt_end); tableformatterbuilder.addformatters(new dictionary{ {sex,r=>r[col2]},//将模板表格中sex对应datatable中的列col2 {km,r=>r[col3]},//将模板表格中km对应datatable中的列col3 {score,r=>r[col4]},//将模板表格中score对应datatable中的列col4 {result,r=>r[col5]}//将模板表格中result对应datatable中的列co5 }); partformatterbuilder partformatterbuilder2 = new partformatterbuilder();//实例化一个可嵌套的局部元素格式化器 partformatterbuilder2.addformatter(name, r => r[col1]);//将模板表格中name对应datatable中的列col1 tableformatterbuilder.appendformatterbuilder(partformatterbuilder2);//添加到可重复表格格式化器中,作为其子格式化器 cellformatterbuilder cellformatterbuilder = new cellformatterbuilder();//实例化一个可嵌套的单元格格式化器 cellformatterbuilder.addformatter(rptdate, r => datetime.today.tostring(yyyy-mm-dd hh:mm));//将模板表格中rptdate的值设置为当前日期 tableformatterbuilder.appendformatterbuilder(cellformatterbuilder);//添加到可重复表格格式化器中,作为其子格式化器 formattercontainers.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, multtable, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板如下:
导出结果如下:
4.
/// /// 测试方法:测试依据复杂模板(含固定表格,可重复表格)+datatable来生成excel (注意:由于excelreport框架限制,目前仅支持模板文件格式为:xls) /// [testmethod] public void testexporttoexcelwithtemplatebylist2() { var schoollevellist = schoollevel.getlist(); var classlist = classinfo.getlist(); string templatefilepath = appdomain.currentdomain.basedirectory + /mb.xls; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 partformatterbuilder partformatterbuilder = new partformatterbuilder(); partformatterbuilder.addformatter(school, 跨越小学); formattercontainers.appendformatterbuilder(partformatterbuilder); tableformatterbuilder tableformatterbuilder = new tableformatterbuilder(schoollevellist, lv);//实例化一个表格格式化器 tableformatterbuilder.addformatters(new dictionary { {lv,r=>r.levelname}, //模板参数与数据源schoollevel属性对应关系,下同 {clscount,r=>r.classcount}, {lvmaster,r=>r.master} }); formattercontainers.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 repeaterformatterbuilder repeaterformatterbuilder = new repeaterformatterbuilder(classlist, lv_begin, lv_end);//实例化一个可重复表格格式化器 repeaterformatterbuilder.addformatters(new dictionary { {class,r=>r.classname}, //模板参数与数据源classinfo属性对应关系,下同 {stucount,r=>r.studentcount}, {clsmaster,r=>r.master}, {lvitem,r=>r.levelname} }); formattercontainers.appendformatterbuilder(repeaterformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, school, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板如下:
导出结果如下:
5.
/// /// 测试方法:测试依据复杂模板(含固定表格,可重复表格中嵌套表格)+datatable来生成excel (注意:由于excelreport框架限制,目前仅支持模板文件格式为:xls) /// [testmethod] public void testexporttoexcelwithtemplatebylist3() { var schoollevellist = schoollevel.getlist(); var classlist = classinfo.getlistwithlevels(); string templatefilepath = appdomain.currentdomain.basedirectory + /mb1.xls; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 partformatterbuilder partformatterbuilder = new partformatterbuilder(); partformatterbuilder.addformatter(school, 跨越小学); formattercontainers.appendformatterbuilder(partformatterbuilder); tableformatterbuilder tableformatterbuilder = new tableformatterbuilder(schoollevellist, lv);//实例化一个表格格式化器 tableformatterbuilder.addformatters(new dictionary { {lv,r=>r.levelname}, //模板参数与数据源schoollevel属性对应关系,下同 {clscount,r=>r.classcount}, {lvmaster,r=>r.master} }); formattercontainers.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 repeaterformatterbuilder repeaterformatterbuilder = new repeaterformatterbuilder(classlist, lv_begin, lv_end); repeaterformatterbuilder.addformatter(lvitem,r=>r.key); tableformatterbuilder tableformatterbuilder2=new tableformatterbuilder(r=>r.value,class); tableformatterbuilder2.addformatter(class,r=>r.classname); tableformatterbuilder2.addformatter(stucount,r=>r.studentcount); tableformatterbuilder2.addformatter(clsmaster,r=>r.master); repeaterformatterbuilder.appendformatterbuilder(tableformatterbuilder2); formattercontainers.appendformatterbuilder(repeaterformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, school, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板如下:
导出结果如下:
6.
/// /// 测试方法:测试依据复杂模板(多工作薄,且含固定表格,可重复表格)+dataset来生成excel,只支持xls /// [testmethod] public void testexporttoexcelwithtemplatebydataset() { var ds = getdataset(); string templatefilepath = appdomain.currentdomain.basedirectory + /mb2.xls; //获得excel模板路径 dictionary formattercontainerdic = new dictionary(); //实例化一个模板数据格式化容器数组,包含两个sheetformattercontainer用于格式化两个工作薄 #region 创建第一个工作薄格式化容器,并设置相关参数对应关系 sheetformattercontainer formattercontainer1 = new sheetformattercontainer(); partformatterbuilder partformatterbuilder = new partformatterbuilder(); partformatterbuilder.addformatter(school, 跨越小学); formattercontainer1.appendformatterbuilder(partformatterbuilder); tableformatterbuilder tableformatterbuilder = new tableformatterbuilder(ds.tables[0].select(), lv);//实例化一个表格格式化器 tableformatterbuilder.addformatters(new dictionary { {lv,r=>r[col1]}, //模板参数与数据源datatable属性对应关系,下同 {clscount,r=>r[col2]}, {lvmaster,r=>r[col3]} }); formattercontainer1.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 repeaterformatterbuilder repeaterformatterbuilder = new repeaterformatterbuilder(ds.tables[1].select(), lv_begin, lv_end);//实例化一个可重复表格格式化器 repeaterformatterbuilder.addformatters(new dictionary { {class,r=>r[col1]}, //模板参数与数据源classinfo属性对应关系,下同 {stucount,r=>r[col2]}, {clsmaster,r=>r[col3]}, {lvitem,r=>r[col4]} }); formattercontainer1.appendformatterbuilder(repeaterformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 formattercontainerdic.add(table1, formattercontainer1);//添加到工作薄格式容器数组中,注意此处的key值为模板上工作薄的名称,此处即为:table1 #endregion #region 创建第二个工作薄格式化容器,并设置相关参数对应关系 sheetformattercontainer formattercontainer2 = new sheetformattercontainer(); //实例化一个模板数据格式化容器 partformatterbuilder partformatterbuilder2 = new partformatterbuilder();//实例化一个局部元素格式化器 partformatterbuilder2.addformatter(title, 跨越it学员);//将模板表格中title的值设置为跨越it学员 formattercontainer2.appendformatterbuilder(partformatterbuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效 cellformatterbuilder cellformatterbuilder2 = new cellformatterbuilder();//实例化一个单元格格式化器 cellformatterbuilder2.addformatter(rptdate, datetime.today.tostring(yyyy-mm-dd hh:mm));//将模板表格中rptdate的值设置为当前日期 formattercontainer2.appendformatterbuilder(cellformatterbuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效 //实例化一个表格格式化器,dt.select()是将datatable转换成datarow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名 tableformatterbuilder tableformatterbuilder2 = new tableformatterbuilder(ds.tables[2].select(), name); tableformatterbuilder2.addformatters(new dictionary{ {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中的列col4 {result,r=>r[col5]}//将模板表格中result对应datatable中的列co5 }); formattercontainer2.appendformatterbuilder(tableformatterbuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效 formattercontainerdic.add(table2, formattercontainer2);//添加到工作薄格式容器数组中,注意此处的key值为模板上工作薄的名称,此处即为:table2 #endregion string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, formattercontainerdic); assert.istrue(file.exists(excelpath)); }
模板如下:
导出结果如下:
二、excelutility类库操作说明(嵌入图片示例)
一、 制作模板(含图片)
1. 制作模板的文件格式需为兼容格式,即:xls或xlt;
2. 模板变量(或称为占位符)定义与之前相同,即:$[变量名];
3. 图片变量定义如下:
a) 绘制一个图形,图形形状尽可能的与要显示的图片相同,比如:印章,则可绘制一个圆形;
b) 图形必需是透明背景,边框可要可不要,建议留着,这样后续调整比较方便,如下图中的蓝色透明背景圆形:
c) 图形大小尽可能与要显示的图片大小相同,如下图示:
由于excel上大小默认采用厘米,而图片一般采用像素,所以需要自己换算一下像素对应的厘米数(也可将excel计算单位设为像素,方法自行网上查找);也可网上下载单位转换工具
另外图形属性建议设置成如下图:
温馨提示:图形形状、属性若未设置一般不影响导出效果,但不排除其它异常情况,图形大小是一定要设置,且尽可能与要显示图形大小(高、宽)相同,否则有可能造成导出变形
代码示例:
/// /// 测试方法:测试依据模板+datatable+图片来生成包含图片的excel,只支持xls /// [testmethod] public void testinsertpic() { datatable dt = getdatatable();//获取数据 string templatefilepath = appdomain.currentdomain.basedirectory + /excel.xls; //获得excel模板路径 sheetformattercontainer formattercontainers = new sheetformattercontainer(); //实例化一个模板数据格式化容器 partformatterbuilder partformatterbuilder = new partformatterbuilder();//实例化一个局部元素格式化器 partformatterbuilder.addformatter(title, 跨越it学员);//将模板表格中title的值设置为跨越it学员d 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 tableformatterbuilder = new tableformatterbuilder(dt.select(), name); tableformatterbuilder.addformatters(new dictionary{ {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中的列col4 {result,r=>r[col5]}//将模板表格中result对应datatable中的列co5 }); formattercontainers.appendformatterbuilder(tableformatterbuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效 string picpath = appdomain.currentdomain.basedirectory + \\tz.png;//图片路径 picturewithshapeformatterbuilder picturebuilder = new picturewithshapeformatterbuilder();//实例化一个图片关联图形格式化器 //picturebuilder.addformatter(picpath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句 picturebuilder.addformatter(picpath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引,列索引,索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片 formattercontainers.appendformatterbuilder(picturebuilder); string excelpath = excelutility.export.toexcelwithtemplate(templatefilepath, table, formattercontainers); assert.istrue(file.exists(excelpath)); }
模板如下:
注意图片若需要为透明背景格式,则必需使用png格式,npoi支持的图片主要格式有:png,jpg
导出结果如下:
温馨提示:
picturebuilder.addformatter(picpath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句
picturebuilder.addformatter(picpath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引(起止),列索引(起止),索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片
如果图形可能随单元格进行位置调整,那么在指定图形区域时需注意,如果图形会随单元格下移,那么结束行索引(minrow)就需要指定一个可能的最大值或不指定,如果图形会随单元格右移,那么结束列索引(mincolumn)就需要指定一个可能的最大值或不指定,如果存在多个图形区域,则上述情况都必需给定具体值(可能的最大值),以免造成区域交叉,从而导致图片显示不正确,如下示例:
//图形可能下移,可能右移,那么将结束行设为可能最大值:60000,结束列设为可能最大值:255
picturebuilder.addformatter(picpath, 5, 60000, 0, 255, false);
//此处只指定开始行与开始列,与上面差不多,但建议使用上面的用法
picturebuilder.addformatter(new picturewithshapeinfo(picpath, new sheetrange() {minrow=5,mincolumn=0 },false));
特别说明:
1.本类库是基于npoi+excelreport,所有功能凡我的类库能够实现的,npoi与excelreport都可以实现,只是用法及复杂程度不同而矣,我封装的目的就是为了降低大家的学习难度,提高使用效率,免费且开源,源代码同步更新至开源社区的git目录中,具体地址请看我该系列之前的文章有列出,在此就不再说明。
2.上述图片关联图形显示功能我是在excelreport基础上增加了一个picturewithshapeformatter类及其相关的类:picturewithshapeinfo、sheetrange,因没有关联git,所以是在本地更新的,这几个类的代码如下:
picturewithshapeformatter:
using npoi.extend;using npoi.hssf.usermodel;using npoi.ss.usermodel;using npoi.xssf.usermodel;using system;using system.collections.generic;using system.linq;using system.text;namespace excelreport{ public class picturewithshapeformatter : elementformatter { private picturewithshapeinfo pictureinfo = null; public picturewithshapeformatter(picturewithshapeinfo pictureinfo) { this.pictureinfo = pictureinfo; } public override void format(sheetadapter sheetadapter) { var sheet = sheetadapter.currentsheet; var shapes = pictureinfo.getshapes(sheet); bool iscompatible = false; if (sheet is hssfsheet) { iscompatible = true; } if (shapes == null || shapes.count = math.abs(_rangemaxrow + _rangeminrow - picturemaxrow - pictureminrow)) && (math.abs(_rangemaxcol - _rangemincol) + math.abs(picturemaxcol - picturemincol) >= math.abs(_rangemaxcol + _rangemincol - picturemaxcol - picturemincol))); } } } /// /// 工作薄区域 /// 作者:zuowenjun /// public class sheetrange { public int? minrow { get; set; } public int? maxrow { get; set; } public int? mincolumn { get; set; } public int? maxcolumn { get; set; } public sheetrange() { } public sheetrange(int minrow, int maxrow, int mincolumn, int maxcolumn) { this.minrow = minrow; this.maxrow = maxrow; this.mincolumn = mincolumn; this.maxcolumn = maxcolumn; } public override bool equals(object obj) { bool equalresult = false; equalresult = base.equals(obj); if (!equalresult) { var othersheetrange = obj as sheetrange; if (othersheetrange != null) { equalresult = (this.minrow = othersheetrange.maxrow && this.mincolumn = othersheetrange.maxcolumn); } } return equalresult; } public override int gethashcode() { return this.tostring().gethashcode(); } public override string tostring() { return string.format(minrow:{0},maxrow:{1},mincolumn:{2},maxcolumn:{3}, this.minrow, this.maxrow, this.mincolumn, this.maxcolumn); } }}
分享我基于npoi+excelreport实现的导入与导出excel类库:excelutility 其它相关文章链接:
分享我基于npoi+excelreport实现的导入与导出excel类库:excelutility 
分享我基于npoi+excelreport实现的导入与导出excel类库:excelutility (续篇)
其它类似信息

推荐信息