NPOI是指构建在POI 3.x版本之上的一个程序,NPOI可以在没有安装Office的情况下对Word或Excel文档进行读写操作。
直接上代码,这里我引用的事1.2.5版本,因为我项目是2.0的,不支持高版本
这里我是转成了datatable类型了,大家可以根据需求不一定要转换,可以直接操作sheet对象
这里要注意 sheet1.LastRowNum 这个是获取最后一行的编号,编号从0开始,也就是说如果是6行获取就是5!!!
这里要注意 sheet1.LastRowNum 这个是获取最后一行的编号,编号从0开始,也就是说如果是6行获取就是5!!!
这里要注意 sheet1.LastRowNum 这个是获取最后一行的编号,编号从0开始,也就是说如果是6行获取就是5!!!
public static DataTable LoadDataFromExcelByNPOI(string fileName)
{
FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate); //读取文件流
HSSFWorkbook workbook = new HSSFWorkbook(fs); //根据EXCEL文件流初始化工作簿
workbook.ForceFormulaRecalculation = true;//这里设置为获取值,就不用获取公式了
var sheet1 = workbook.GetSheetAt(0); //获取第一个sheet
DataTable table = new DataTable();//
var row1 = sheet1.GetRow(0);//获取第一行即标头
int cellCount = row1.LastCellNum; //第一行的列数
//把第一行的数据添加到datatable的列名
for (int i = row1.FirstCellNum; i < cellCount; i++)
{
string columnVaulue = "F" + (i + 1);
if (row1.GetCell(i)!=null && !string.IsNullOrEmpty(row1.GetCell(i).StringCellValue))
{
columnVaulue = row1.GetCell(i).StringCellValue;
}
DataColumn column = new DataColumn(columnVaulue);
table.Columns.Add(column);
}
int rowCount = sheet1.LastRowNum; //总行数
//把每行数据添加到datatable中
for (int i = (sheet1.FirstRowNum + 1); i <= sheet1.LastRowNum; i++)
{
var row = sheet1.GetRow(i);
DataRow dataRow = table.NewRow();
for (int j = row.FirstCellNum; j < cellCount; j++)
{
if (row.GetCell(j) != null)
{
row.GetCell(j).SetCellType(NPOI.SS.UserModel.CellType.STRING);//这里设置为获取值,就不用获取公式了
dataRow[j] = row.GetCell(j).ToString();
}
}
table.Rows.Add(dataRow);
}
//到这里 table 已经可以用来做数据源使用了
workbook = null; //清空工作簿--释放资源
sheet1 = null; //清空sheet
return table;
}
保存操作
public void ExportExcel(List list, string filePath)
{
try
{
//判断是否存在这么一个文件夹,没有的话,就创建一下。
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
using (Stream fs = new FileStream(filePath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + @".xls", FileMode.Create, FileAccess.Write))
{
XSSFWorkbook work = new XSSFWorkbook();
//创建一个文件
ISheet sheet = work.CreateSheet("特急送");
//创建一个sheet,并命名
//添加表头 数 据
IRow row = sheet.CreateRow(0);
//创建sheet中的一行,0表示第一行
row.Height = 20 * 20;
//下面的cell是指单元格,表示上面刚刚创建的那一行中的单元格
//其中0,1,2表示,这一行横着数第几个单元格,索引从0开始
row.CreateCell(0, CellType.String).SetCellValue("第一列");
row.CreateCell(1, CellType.String).SetCellValue("第二列");
row.CreateCell(9, CellType.String).SetCellValue("第三列");
//下面是设置样式
var cellStyle = work.CreateCellStyle();
var font = work.CreateFont();
font.Color = 10;
font.FontHeightInPoints = 13;
cellStyle.SetFont(font);
cellStyle.FillForegroundColor = 22;
cellStyle.FillPattern = FillPattern.SolidForeground;
cellStyle.BorderTop = cellStyle.BorderBottom = cellStyle.BorderLeft= cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
cellStyle.BottomBorderColor = cellStyle.LeftBorderColor = cellStyle.RightBorderColor = cellStyle.TopBorderColor = 68;
int[] colWidth = { 11, 11, 11, 9, 9, 17, 17, 17, 15, 32 };
for (int i = 0; i < row.Cells.Count; i++)
{
row.Cells[i].CellStyle = cellStyle;
sheet.SetColumnWidth(i, colWidth[i] * 256);
}
//添加数据,相关注释参考 表头
for (int i = 0; i < list.Count(); i++)
{
row = sheet.CreateRow(i + 1);
row.CreateCell(0, CellType.String).SetCellValue("第1列的值");
row.CreateCell(1, CellType.String).SetCellValue("第2列的值");
row.CreateCell(2, CellType.String).SetCellValue("第3列的值");
}
work.Write(fs);
}
}
catch (Exception ex)
{
MessageBox.Show("导出异常" + ex.ToString(), "警告", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
}
}
方法的一个总览
//创建工作薄
HSSFWorkbook book = new HSSFWorkbook();
//添加一个sheet
ISheet sheet1 = book.CreateSheet("Sheet1");
#region 创建一个样式
ICellStyle title = book.CreateCellStyle();
//背景灰色
title.FillForegroundColor = HSSFColor.Grey50Percent.Index;
title.FillPattern = FillPattern.SolidForeground;
//添加边框
title.BorderBottom = BorderStyle.Thin;
title.BorderLeft = BorderStyle.Thin;
title.BorderRight = BorderStyle.Thin;
title.BorderTop = BorderStyle.Thin;
//文本居中
title.Alignment = HorizontalAlignment.Center;
//垂直居中
title.VerticalAlignment = VerticalAlignment.Justify;
//创建一个字体
IFont font1 = book.CreateFont();
//字体加粗
font1.Boldweight = (short)FontBoldWeight.Bold;
//字体大小 16
font1.FontHeightInPoints = 16;
title.SetFont(font1);
#endregion
//创建第一行数据
IRow row0 = sheet1.CreateRow(0);
//设置行高30
row0.Height = 30 * 20;
//在第一行中创建第一个格子
ICell titlecell = row0.CreateCell(0);
titlecell.SetCellValue("名称内容");
#region 设置列宽
//设置列宽 SetColumnWidth(列的索引号从0开始, N * 256) 第二个参数的单位是1/256个字符宽度。例:将第四列宽度设置为了30个字符
sheet1.SetColumnWidth(0, 6 * 256);
#endregion
#region 打印相关设置
//设置打印区域sheetnum, int first row,int last row,int first col,int last col
book.SetPrintArea(0, 0, 6, 0, sheet1.LastRowNum);
// 设置固定列头
sheet1.RepeatingRows = new CellRangeAddress(0, 6, 0, 6);
//设置页码
//sheet1.PrintSetup.UsePage = true;
// 设置横向打印 纵向为false
sheet1.PrintSetup.Landscape = false;
// 设置页高为自动
//sheet1.PrintSetup.FitHeight = -1;
// 设置页宽为自动
//sheet1.PrintSetup.FitWidth = -1;
// 设置缩放比例
sheet1.PrintSetup.Scale = 100;
// 设置纸张尺寸 A4 = 9
sheet1.PrintSetup.PaperSize = 9;
// 设置不自适应
//sheet1.FitToPage = true;
// 设置打印边距
sheet1.SetMargin(MarginType.RightMargin, (double)0.5);
sheet1.SetMargin(MarginType.TopMargin, (double)0.5);
sheet1.SetMargin(MarginType.LeftMargin, (double)0.5);
sheet1.SetMargin(MarginType.BottomMargin, (double)0.5);
//设置页脚打印
sheet1.Footer.Left = "客户至上,服务第一是我们的宗旨;";
//设置页脚
(一)传统操作Excel遇到的问题:
1、如果是.NET,需要在服务器端装Office,且及时更新它,以防漏洞,还需要设定权限允许.NET访问COM+,如果在导出过程中出问题可能导致服务器宕机。
2、Excel会把只包含数字的列进行类型转换,本来是文本型的,Excel会将其转成数值型的,比如编号000123会变成123。
3、导出时,如果字段内容以“-”或“=”开头,Excel会把它当成公式进行,会报错。
4、Excel会根据Excel文件前8行分析数据类型,如果正好你前8行某一列只是数字,那它会认为该列为数值型,自动将该列转变成类似1.42702E+17格式,日期列变成包含日期和数字的。
(二)使用NPOI的优势
1、您可以完全免费使用该框架
2、包含了大部分EXCEL的特性(单元格样式、数据格式、公式等等)
3、专业的技术支持服务(24*7全天候) (非免费)
4、支持处理的文件格式包括xls, xlsx, docx.
5、采用面向接口的设计架构( 可以查看 NPOI.SS 的命名空间)
6、同时支持文件的导入和导出
7、基于.net 2.0 也支持xlsx 和 docx格式(当然也支持.net 4.0)
8、来自全世界大量成功且真实的测试Cases
9、大量的实例代码
11、你不需要在服务器上安装微软的Office,可以避免版权问题。
12、使用起来比Office PIA的API更加方便,更人性化。
13、你不用去花大力气维护NPOI,NPOI Team会不断更新、改善NPOI,绝对省成本。
14、不仅仅对与Excel可以进行操作,对于doc、ppt文件也可以做对应的操作
NPOI之所以强大,并不是因为它支持导出Excel,而是因为它支持导入Excel,并能“理解”OLE2文档结构,这也是其他一些Excel读写库比较弱的方面。通常,读入并理解结构远比导出来得复杂,因为导入你必须假设一切情况都是可能的,而生成你只要保证满足你自己需求就可以了,如果把导入需求和生成需求比做两个集合,那么生成需求通常都是导入需求的子集,这一规律不仅体现在Excel读写库中,也体现在pdf读写库中,目前市面上大部分的pdf库仅支持生成,不支持导入。