NPOI很早就出名了,但是一直以为第三方的不可能有微软的效率高,所以一直都用COM来处理EXCEL。

直到某天处理一个大量数据的EXCEL,发现NPOI生成的数据几乎是1秒内就完成了,比传统方法快了几百倍。

惊喜万分,开始学习NPOI的使用,也希望留下一些东西供别人学习。



一:​​创建新EXCEL文件​​,用NPOI创建一个新的EXCEL文件。


下载地址就不再赘述了。

如果只是简单的处理的话,只需要引用下载压缩包里的

NPOI.dll 和 ICSharpCode.SharpZipLib.dll 

两个文件而已。


好了,开始。

第一步,引用空间



[csharp] 

​view plain​​ 

​copy​​    



  1. using NPOI.HSSF.UserModel;
  2. using NPOI.SS.UserModel;


第二步,创建工作簿(workbook)和sheet





[csharp] 

​view plain​​ 

​copy​​    



  1. HSSFWorkbook wk = new HSSFWorkbook();
  2. //创建一个Sheet
  3. ISheet sheet = wk.CreateSheet("例子");


第三步,创建行和单元格





[csharp] 

​view plain​​ 

​copy​​    



  1. //在第一行创建行
  2. IRow row = sheet.CreateRow(0);
  3. //在第一行的第一列创建单元格
  4. ICell cell = row.CreateCell(0);


在NPOI里,IRow和ICell是表格结构里的基本元素,必须先通过Create函数创建后才能使用,不然会报错。

  • 知识点
  • 因为在excel里,在某个位置有没有单元格,和单元格里有没有值,这两个是分开保存的。“是否有单元格”也是需要保存的信息之一,也同样占用文件大小。单元格是一个无形的容器,必须首先有容器,才能往里头存放值。
  • 曾经见过一个错误的例子,导出的excel只有一行数据,但是文件大小超过十几MB。就是因为在导出的时候,程序员没有弄清楚单元格和值的区别,以为空单元格不占大小,把65535行的所有格子都创建了,大量的空白行导致文件很大。
  • 实际编程中请注意这一点,需要使用的行才创建,需要使用的单元格才创建。



接下来我们可以使用这个函数对单元格赋值。



[csharp] 

​view plain​​ 

​copy​​    



  1. cell.SetCellValue("测试");


值得注意的是,SetCellValue的重载中支持




  • bool
  • DateTime
  • double
  • string
  • IRichTextString


这几种格式的参数,但是不像Excel COM一样支持object。所以赋值的时候必须先做好类型转换。


最后,将做好的这个EXCEL保存到硬盘上。



[csharp] 

​view plain​​ 

​copy​​    



  1. //打开一个xls文件,如果没有则自行创建,如果存在myxls.xls文件则在创建时不要打开该文件
  2. using (FileStream fs = File.OpenWrite("d:\\excel.xls"))
  3. {
  4. wk.Write(fs);//向打开的这个xls文件中写入并保存。
  5. }


这样就完成了最基本的创建,写入,保存。

二:​​编辑既存的EXCEL文件​​



在这一篇里,我们读入上一篇教程中生成的EXCEL,然后以其做为模版,修改之后保存为另一份EXCEL


第一步



[csharp] 

​view plain​​ 

​copy​​    



  1. //上一篇教程中生成的文件
  2. string tempPath = "d:\\excel.xls";
  3. HSSFWorkbook wk = null;
  4. using (FileStream fs = File.Open(tempPath, FileMode.Open,
  5. FileAccess.Read, FileShare.ReadWrite))
  6. {
  7. //把xls文件读入workbook变量里,之后就可以关闭了
  8. wk = new HSSFWorkbook(fs);
  9. fs.Close();
  10. }



第二步

在读入之后,操作HSSFWorkbook这个类就和第一篇教程里一样了。

必须要遵循的一个规则是,如果你要编辑的行和单元格,原本没有值,或者从未创建过的,就必须先创建。

如:

我要使用第二行第一列的单元格,在上一篇教程中并未对这个位置进行创建,那么必须先创建。



[csharp] 

​view plain​​ 

​copy​​    



  1. //在第二行创建行
  2. IRow row = sheet.CreateRow(1);
  3. //在第二行的第一列创建单元格
  4. ICell cell = row.CreateCell(0);



之后这个cell才能被使用。


  • 那么如果我不创建,直接使用会怎么样呢?
  • 答:sheet.GetRow(1)取回来的值为null,在null上再使用GetCell(0)就会报空对象的错误。


在上一篇教程中,我们已经对该文件的第一行第一列的这个位置创建过单元格,并且赋值,所以可以直接使用,采用下面的方式。



[csharp] 

​view plain​​ 

​copy​​    



  1. //获取第一行
  2. IRow row = sheet.GetRow(0);
  3. //在第一行获取第一列单元格
  4. ICell cell = row.GetCell(0);

上面两种写法也可以简写成如下的方式



[csharp] 

​view plain​​ 

​copy​​    



  1. //创建第二行,第一列
  2. ICell cell = sheet.CreateRow(1).CreateCell(0);
  3. //获取第一行,第一列
  4. ICell cell = sheet.GetRow(0).GetCell(0);


然后使用cell.SetCellValue()函数对其赋值即完成编辑。


当然,赋值语句也可以和上述语句并作一行书写。例如



[csharp] 

​view plain​​ 

​copy​​    



  1. sheet.GetRow(0).GetCell(0).SetCellValue("编辑的值");



第三步

编辑完之后需要保存



[csharp] 

​view plain​​ 

​copy​​    



  1. using (FileStream fileStream = File.Open("d:\\excel.xls",
  2. FileMode.OpenOrCreate, FileAccess.ReadWrite))
  3. {
  4. wk.Write(fileStream);
  5. fileStream.Close();
  6. }



这样就完成了读入已有文件,编辑,保存。


三:EXCEL 基本格式设置之ICellStyle



前两篇,我们已经学习了如何用NPOI来创建和编辑Excel,并且已经熟悉了HSSFWorkbook,ISheet,IRow和ICell。

接下来我们把它变得漂亮一点。


ICellStyle——单元格样式

当我们拥有了一个HSSFWorkbook实例之后。我们可以通过下面的方式来创建一个样式变量。



[csharp] 

​view plain​​ 

​copy​​    



  1. HSSFWorkbook wk = new HSSFWorkbook();//你用来操作的HSSFWorkbook的实例
  2. ICellStyle cellStyle = wk.CreateCellStyle();


这样我们就创建好了一个样式变量。


  • 注意:
  • 创建样式是基于HSSFWorkbook,而不是ISheet。


这个ICellStyle里有些什么属性可以设置呢?

NPOI 2.0 使用教程详解_彭世瑜_新浪博客_python

没错,所有你能想到的对于单元格的格式样式的设置都在里面。种类非常多,命名也比较直白,比如:对齐方式,上下左右边框线的颜色和样式,字体等等。

写个例子给大家看看。


[csharp] 

​view plain​​ 

​copy​​    



  1. ICellStyle cellStyle = wk.CreateCellStyle();
  2. //设置单元格上下左右边框线
  3. cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
  4. cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
  5. cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
  6. cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
  7. //文字水平和垂直对齐方式
  8. cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
  9. cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
  10. //是否换行
  11. //cellStyle.WrapText = true;
  12. //缩小字体填充
  13. cellStyle.ShrinkToFit = true;


大部分的设置都有相应的枚举类型可以选择,比如这个边框样式Thin,实际上就是我们最常见的单线最细的那种边框,你也可以根据需要设置成虚线,点线,双线等等。


  • 注意:
  • “是否换行”和“缩小字体填充”本身是互斥的两个设置,如果同时设为True,则只有“是否换行”会生效。


设置好了格式变量,就可以把它应用到单元格上去。通过对ICell的CellStyle赋值实现。


[csharp] 

​view plain​​ 

​copy​​    



  1. ICell Cell = sheet.CreateRow(0).CreateCell(0);
  2. Cell.CellStyle = cellStyle;
  3. Cell.SetCellValue("测试格式效果");


设置格式就是这么简单。


你可能会问了,如果我需要设置一大片的单元格都是这个格式,该不会要一个一个的设置吧?

很悲催的告诉你,没错,目前暂未发现有直接批量设置格式的方法。不过考虑到本身你也需要一个一个去创建Cell,所以顺便赋值上去也不是什么很麻烦的事情。


  • 提到ICellStyle就不能不提到一个需要注意的地方:
  • 通过某些现象我们曾经观察到,ICellStyle的创建是有数量限制的,换句话说,一个Excel文件里负责保存样式的空间是有限的,样式也占用一定的文件大小。
  • 那么我们就应该注意样式的重复利用,​相同的样式尽量不要创建两份​,直接赋值同一个就可以了,在编写代码的时候注意样式变量的作用域。


对于只有少部分不相同的样式,我们可以使用CloneStyleFrom()方法来克隆前一个样式,而只修改需要修改的部分,减少重复代码。



[csharp] 

​view plain​​ 

​copy​​    



  1. ICellStyle newCellStyle = wk.CreateCellStyle();
  2. newCellStyle.CloneStyleFrom(cellStyle);
  3. newCellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left;


关于ICellStyle已经讲完,希望大家喜欢。


不需要释放,不需要安装EXCEL。速度极快,实在很方便。