近期的两个项目都有关于NPOI的功能,经过了一点学习,自己也摸索了一会,感觉还有点意思。现在将部分代码分享一下。一部分是C#代码,一部分是VB.Net的,懒得修改了,基本上都是从项目文件中copy出来的。如果错漏,请指教。
概述:
1、整个Excel表格:WorkBook(工作薄),包含的叫页(工作表):Sheet;行:Row;单元格Cell。
2、NPOI是POI的C#版本,NPOI的行和列的index都是从0开始
3、POI读取Excel有两种格式一个是HSSF,另一个是XSSF。 HSSF和XSSF的区别如下:
HSSF is the POI Project's pure Java implementation of the Excel '97(-2007) file format.
XSSF is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.
即:HSSF适用2007以前的版本,XSSF适用2007版本及其以上的。
4、NPOI能够在没有安装微软Office的情况下读写Office文件,支持的文件格式包括xls, doc, ppt等。
引用:
Manage NuGet packages -> NPOI
读取excel:
1、Asp.Net使用FileUpload控件上传excel文件(VB.Net代码):
Dim fileOriginalPath As String = excelUploader.PostedFile.FileName Dim fileName As String = excelUploader.FileName Dim extension = Path.GetExtension(fileOriginalPath).ToLower() Dim workbook As IWorkbook If (extension = ".xlsx") Then 'excel 2007 workbook = New XSSFWorkbook(excelUploader.PostedFile.InputStream) Else 'excel 2003 workbook = New HSSFWorkbook(excelUploader.PostedFile.InputStream) End If
2、WPF读取本地excel文件:
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { hssfworkbook = new HSSFWorkbook(file); } //其实HSSFWorkbook/XSSFWorkbook的构造方法可以直接传入FileInfo做参数
3、WPF读取嵌入在资源文件的excel表格
public XSSFWorkbook ReadDemoExcel() { MemoryStream ms = new MemoryStream(Properties.Resources.QNetTimesheet); ms.Position = 0; XSSFWorkbook book = new XSSFWorkbook(ms); return book; }
获取表(sheet)、行(row)、单元格(cell):
ISheet sheet = book.GetSheetAt(0) //除了根据index,还可以根据名字获取:book.GetSheet("da") IRow row = sheet.GetRow(0); ICell cell = row.GetCell(4); //row.Cells(i)方法也可以获取单元格, 但是此方法会跳过null的单元格。譬如,如果cell0跟cell3之间有一个单元格是null,那么row.Cells(3)就不会是你想要的那个cell...Please use row.GetCell(i)!!!!! book.SetSheetName(1, "新名字");//修改sheet名字 IRow newRow = sheet.CreateRow(i);//创建新行 int rowIndex = sheet.LastRowNum;//最后一行的index
单元格的相关操作:
ICell dateCell = row.CreateCell(0); dateCell.SetCellValue(cardInfoList[i].Date); ICell dayCell = row.CreateCell(1); dayCell.CellFormula = string.Format("WEEKDAY(A{0})", row.RowNum + 1);//设置公式, 并不需要“=”号 ICell totalHoursCell = row.CreateCell(6); totalHoursCell.CellFormula = string.Format("SUM(G{0}:G{1})", x, y);//设置公式
设置单元格样式(CellStyle):
private ICellStyle GetCellDataStyle(IWorkbook book) { ICellStyle cs = book.CreateCellStyle(); cs.BorderBottom = BorderStyle.Thin; cs.BorderLeft = BorderStyle.Thin; cs.BorderRight = BorderStyle.Thin; cs.BorderTop = BorderStyle.Thin; cs.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.LightYellow.Index;//单元格背景色 cs.FillPattern = FillPattern.SolidForeground; cs.DataFormat = 1;//在excel中可以Format Cells->Caregory->Custom设置Type使得单元格对数据显示不同的格式,比如可以设置显示成整形、金额、浮点数或者星期几等等等,可以看下面的“DataFormat”部分 cs.Alignment = HorizontalAlignment.Center;//水平对齐 return cs; } cell.CellStyle = GetCellDataStyle(book);//赋值
单元格的DataFormat:
可以看到,对同一个单元格,设置不同的DataFormat,最终显示的内容是不同的。在NPOI中,我们可以通过对单元格设置其DataFormat属性来达到我们的目的。
此属性是int类型,网上的例子不齐全。现实中,我们可以先创建一个excel表并且在excel中操作单元格使得其达到我们的要求,然后用NPOI读取得知其DataFormat。
嗯,第一张截图显示Wednesday是我用公式=WEEKDAY(A7)根据日期计算并显示的,DataFormat是185
/* 0, "General" 1, "0" 2, "0.00" 3, "#,##0" 4, "#,##0.00" 5, "($#,##0_);($#,##0)" 6, "($#,##0_);[Red]($#,##0)" 7, "($#,##0.00);($#,##0.00)" 8, "($#,##0.00_);[Red]($#,##0.00)" 9, "0%" 0xa, "0.00%" 0xb, "0.00E+00" 0xc, "# ?/?" 0xd, "# ??/??" 0xe, "m/d/yy" 0xf, "d-mmm-yy" 0x10, "d-mmm" 0x11, "mmm-yy" 0x12, "h:mm AM/PM" 0x13, "h:mm:ss AM/PM" 0x14, "h:mm" 0x15, "h:mm:ss" 0x16, "m/d/yy h:mm" // 0x17 - 0x24 reserved for international and undocumented 0x25, "(#,##0_);(#,##0)" 0x26, "(#,##0_);[Red](#,##0)" 0x27, "(#,##0.00_);(#,##0.00)" 0x28, "(#,##0.00_);[Red](#,##0.00)" 0x29, "_(*#,##0_);_(*(#,##0);_(* "-"_);_(@_)" 0x2a, "_($*#,##0_);_($*(#,##0);_($* "-"_);_(@_)" 0x2b, "_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)" 0x2c, "_($*#,##0.00_);_($*(#,##0.00);_($*"-"??_);_(@_)" 0x2d, "mm:ss" 0x2e, "[h]:mm:ss" 0x2f, "mm:ss.0" 0x30, "##0.0E+0" 0x31, "@" - This is text format. 0x31 "text" - Alias for "@" */
将excel内容转换为DataTable(VB.Net代码):
Private Function GetDataTableFromExcel(workbook As IWorkbook) As DataTable Dim sheet = workbook.GetSheetAt(0) Dim rows = sheet.GetRowEnumerator() Dim dt = New DataTable() Dim j As Int16 Dim headerRow = sheet.GetRow(0) For j = 0 To headerRow.Cells.Count - 1 'headerRow.LastCellNum - 1 Dim columnName As String = headerRow.Cells(j).ToString() If Not (j = headerRow.Cells.Count - 1 And String.IsNullOrEmpty(columnName)) Then dt.Columns.Add(columnName) End If Next rows.MoveNext() While rows.MoveNext() Dim row As IRow row = rows.Current Dim isRowEmpty As Boolean = IsEmptyRow(row) If isRowEmpty Then Continue While 'do not add empty row to data table End If Dim dr As DataRow dr = dt.NewRow() Dim i As Int16 For i = 0 To dt.Columns.Count - 1 Dim cell As ICell cell = row.GetCell(i) 'row.Cells(i), this method will ignore the null column automatically...Please use row.GetCell(i)!!!!! If cell Is Nothing Then dr(i) = "" Else Try Select Case cell.CellType Case CellType.Blank dr(i) = "" Case CellType.String dr(i) = cell.StringCellValue Case CellType.Numeric If DateUtil.IsCellDateFormatted(cell) Then dr(i) = cell.DateCellValue Else dr(i) = cell.NumericCellValue End If Case Else dr(i) = cell.ToString() End Select Catch ex As Exception dr(i) = "" End Try End If Next dt.Rows.Add(dr) End While Return dt End Function Private Function IsEmptyRow(row As IRow) As Boolean Dim isEmpty As Boolean = True Dim i As Int16 For i = 0 To row.Cells.Count - 1 Dim cell As ICell cell = row.GetCell(i) If cell IsNot Nothing Then If cell.CellType <> CellType.Blank Then isEmpty = False Exit For End If End If Next Return isEmpty End Function
将NPOI生成的excel内容保存为文件:
1、WPF程序将excel内容保存为本地文件:
XSSFWorkbook excelBook = npoiHelper.CreateExcel(); using (MemoryStream MS = new MemoryStream()) { excelBook.Write(MS); byte[] excelBytes = MS.ToArray(); string excelPath = "C:Users est.xlsx"; using (FileStream fs = new FileStream(excelPath, FileMode.Create, FileAccess.Write)) { fs.Write(excelBytes, 0, excelBytes.Length); } }
2、Asp.net服务器返回文件让用户保存(VB.Net代码):
Dim response As HttpResponse = HttpContext.Current.Response response.Clear() response.ClearHeaders() response.ClearContent() response.Charset = "" response.ContentType = "application/vnd.ms-excel" response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}.xls", HttpUtility.UrlEncode(title + "_" + DateTime.Now.ToString("yyyy-MM-dd HH-mm"), System.Text.Encoding.UTF8))) Dim MS = New MemoryStream() book.Write(MS) response.BinaryWrite(MS.ToArray()) response.End() response.Flush() MS.Close() MS.Dispose()