近期的兩個項目都有關於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\test.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()