比NPOI更喜欢的Excel元件-EPPlus!
前阵子发表 【潜盾机】将档案结构汇成Excel文件,从网友佑翔的留言(特此感谢),认识了一颗被我错过的l好组件 -- EPPlus!
NPOI源于POI,在很多接口设计上,带点Java的观点与风格,虽然能实现各项Excel操作,但函数接口及呼叫步骤,总让.NET老鸟感觉不顺手,就像用筷子吃手扒鸡一样别扭。例如: 要写入文字到新的Cell,必须先CreateRow(),再CreateCell(),而不像在Excel VBA透过.Cells(rowIndex, colIndex)一次到位。
LinqToExcel的出现为读取Excel提供方便的额外选择,能用熟悉的LINQ语法查询Excel内容是件畅快的事,只可惜LinqToExcel只限于读取,要产生Excel,还是得回归NPOI。
EPPlus是一个起始于2009年底的Open Source项目,目标锁定在服务器端产生Office Open XML Excel檔(Excel 2007/2010的xlsx,不包含Excel 2003 xls),提供比NPOI更直觉、更简便的API接口! 用.Cells[rowIndex, colIndex]就能直接存取字段,甚至用.Cells[r1, c1, r2, c2]就能取得一段选取范围,再一口气改变它们的样式;而要指定字型颜色时,使用Cells[…].Style.Font.Color.SetColor(Color.Red)就能搞定,不像NPOI需要CreateFont(), CreateCellStyle(), SetFont(), SetCellStyle()一长串操作。这才是.NET客心中理想的好组件呀~~
不过我不禁好奇,为何先前很少听人提起,几无知名度。私自揣摩,猜想可能与EPPlus只支持xlsx,无法兼容于Excel 2003的xls格式,在需顾及不特定使用群时会有Excel版本门坎的考虑。(虽然微软提供免费的Excel检视工具,但需要额外安装仍会有部署面的考虑) 另一方面,这个组件采用LGPL授权,代表如果要包含在产品中散布,产品也必须Open Source(非100%要Open Source,授权限制可参见下方newbie的留言),也会造成一些软件厂商采用上的疑虑。再者,微软本身提供Open XML SDK,已涵盖Excel档的操作,有些开发者已直接采用SDK,没想到再花时间评估更便捷组件(呼应了我在前篇文章的感叹,有小锦囊后真的会让人错过其他更犀利的选择),也可能是原因之一。
依我的看法,随着时光飞逝,旧版Excel兼容的重要性会逐年下降,而应用于网站时,只要不是贩卖网站程序本体,倒不必担忧LGPL的限制(可参照先前的讨论)。至于与Open XML SDK相比,初看语法,EPPlus确实如网友所说,具有"只见新人笑,不见旧人哭"的魅力! 真的可以跟NPOI说Bye Bye啰,在直觉易用上也已把Open XML SDK比下去。总评之后,EPPlus应是可以安心采用的解决方案。
好东西当然要也要实测体验一下威力,就同样用上回的档案结构导出Excel案例吧! 这回改用EPPlus来处理写成Excel的部分。
要在项目中引用EPPlus,最快的方法一样是透过NuGet: (还不会用NuGet的人,有没有觉得自己已经输在起跑点上?)
//加入扩充方法: SetQuickStyle,指定前景色/背景色/水平对齐
private static void SetQuickStyle(this ExcelRange range,
Color foreColor,
Color bgColor = default(Color),
ExcelHorizontalAlignment hAlign = ExcelHorizontalAlignment.Left)
{
range.Style.Font.Color.SetColor(foreColor);
if (bgColor != default(Color))
{
range.Style.Fill.PatternType = ExcelFillStyle.Solid;
range.Style.Fill.BackgroundColor.SetColor(bgColor);
}
range.Style.HorizontalAlignment = hAlign;
}
/// <summary>
/// 将目录下的目录档案结构导出成Excel工作表
/// </summary>
/// <param name="dirPath">要导出的目录路径</param>
/// <param name="excelPath">导出Excel路径</param>
/// <param name="filter">过滤函数,传入Path进行判断,传回true时表排除</param>
/// <returns></returns>
public static void WebTreeToExcel(
string dirPath, string excelPath,
Func<string, bool> filter = null)
{
//将目录结构整理成列表
List<WebItem> list = new List<WebItem>();
explore(list, dirPath, 0);
//建立Excel
using (ExcelPackage p = new ExcelPackage())
{
ExcelWorksheet sheet = p.Workbook.Worksheets.Add("Site Tree");
int colIdx = 1;
foreach (string colName in "Path;File;Description".Split(';'))
{
sheet.Cells[1, colIdx++].Value = colName;
}
//修改标题栏Style
sheet.Cells[1, 1, 1, 3].SetQuickStyle(Color.Yellow, Color.Green,
ExcelHorizontalAlignment.Center);
int rowIdx = 2;
foreach (var item in list)
{
//若bypass检测传回true,则略过该笔
if (filter != null && filter(item.Path))
continue;
//将Path放在第一栏(稍后隐藏)
sheet.Cells[rowIdx, 1].Value = item.Path;
//存入文件名或目录名
sheet.Cells[rowIdx, 2].Value =
new String(' ', item.Layer * 4) + item.Name;
if (item.IsFolder)
{
sheet.Cells[rowIdx, 2].SetQuickStyle(Color.Blue);
}
rowIdx++;
}
//第一栏隐藏
sheet.Column(1).Hidden = true;
//自动伸缩栏宽
sheet.Column(2).AutoFit();
sheet.Column(2).Width += 2;
sheet.Column(3).Width = 50;
//写入档案
p.SaveAs(new FileInfo(excelPath));
}
Color foreColor,
Color bgColor = default(Color),
ExcelHorizontalAlignment hAlign = ExcelHorizontalAlignment.Left)
{
range.Style.Font.Color.SetColor(foreColor);
if (bgColor != default(Color))
{
range.Style.Fill.PatternType = ExcelFillStyle.Solid;
range.Style.Fill.BackgroundColor.SetColor(bgColor);
}
range.Style.HorizontalAlignment = hAlign;
}
/// <summary>
/// 将目录下的目录档案结构导出成Excel工作表
/// </summary>
/// <param name="dirPath">要导出的目录路径</param>
/// <param name="excelPath">导出Excel路径</param>
/// <param name="filter">过滤函数,传入Path进行判断,传回true时表排除</param>
/// <returns></returns>
public static void WebTreeToExcel(
string dirPath, string excelPath,
Func<string, bool> filter = null)
{
//将目录结构整理成列表
List<WebItem> list = new List<WebItem>();
explore(list, dirPath, 0);
//建立Excel
using (ExcelPackage p = new ExcelPackage())
{
ExcelWorksheet sheet = p.Workbook.Worksheets.Add("Site Tree");
int colIdx = 1;
foreach (string colName in "Path;File;Description".Split(';'))
{
sheet.Cells[1, colIdx++].Value = colName;
}
//修改标题栏Style
sheet.Cells[1, 1, 1, 3].SetQuickStyle(Color.Yellow, Color.Green,
ExcelHorizontalAlignment.Center);
int rowIdx = 2;
foreach (var item in list)
{
//若bypass检测传回true,则略过该笔
if (filter != null && filter(item.Path))
continue;
//将Path放在第一栏(稍后隐藏)
sheet.Cells[rowIdx, 1].Value = item.Path;
//存入文件名或目录名
sheet.Cells[rowIdx, 2].Value =
new String(' ', item.Layer * 4) + item.Name;
if (item.IsFolder)
{
sheet.Cells[rowIdx, 2].SetQuickStyle(Color.Blue);
}
rowIdx++;
}
//第一栏隐藏
sheet.Column(1).Hidden = true;
//自动伸缩栏宽
sheet.Column(2).AutoFit();
sheet.Column(2).Width += 2;
sheet.Column(3).Width = 50;
//写入档案
p.SaveAs(new FileInfo(excelPath));
}
一模一样的结果,跟上回的NPOI写法相比,是不是清爽顺眼很多呢? 在以xlsx为主的网站应用场合,大家就大胆用下去吧!

浙公网安备 33010602011771号