每一個xls都對應一個唯一的HSSFWorkbook,每一個HSSFWorkbook會有若干個HSSFSheet,而每一個HSSFSheet包含若干HSSFRow(Excel 2003中不得超過65535行),每一個HSSFRow又包含若干個HSSFCell(Excel 2003中不得超過256列)。
為了遍歷所有的單元格,我們就得獲得某一個HSSFSheet的所有HSSFRow,通常可以用HSSFSheet.GetRowEnumerator()。如果要獲得某一特定行,可以直接用HSSFSheet.GetRow(rowIndex)。另外要遍歷我們就必須知道邊界,有一些屬性我們是可以用的,比如
HSSFSheet.FirstRowNum(工作表中第一個有數據行的行號)、HSSFSheet.LastRowNum(工作表中最后一個有數據行的行號)、HSSFRow.FirstCellNum(一行中第一個有數據列的列號)、HSSFRow.LastCellNum(一行中最后一個有數據列的列號)。
首先我們要准備一個用於打開文件流的函數InitializeWorkbook,由於文件讀完后就沒用了,所以這里直接用using。
using (var file = new FileStream(path, FileMode.Open, FileAccess.Read)) { var hssfworkbook = new HSSFWorkbook(file); var sheet = hssfworkbook.GetSheetAt(0); var rows = sheet.GetRowEnumerator(); var dt = new DataTable(); for (var j = 0; j < 5; j++) { dt.Columns.Add(Convert.ToChar(((int) 'A') + j).ToString()); } while (rows.MoveNext()) { var row = (HSSFRow) rows.Current; var dr = dt.NewRow(); for (var i = 0; i < row.LastCellNum; i++) { var cell = row.GetCell(i); if (cell == null) { dr[i] = null; } else { dr[i] = cell.ToString(); } } dt.Rows.Add(dr); } }
上面的結構大家都應該能看懂吧,無非就是先遍歷行,再遍歷行中的每一列。這里引出了一個難點,由於Excel的單元格有好幾種類型,類型不同顯示的東西就不同,具體的類型有 布爾型、數值型、文本型、公式型、空白、錯誤。
public enum HSSFCellType { Unknown = -1, NUMERIC = 0, STRING = 1, FORMULA = 2, BLANK = 3, BOOLEAN = 4, ERROR = 5 }
這里的HSSFCellType描述了所有的類型,但細心的朋友可能已經發現了,這里沒有日期型,這是為什么呢?這是因為Excel底層並沒有一定日期型,而是通過數值型來替代,至於如何區分日期和數字,都是由文本顯示的樣式決定的,在NPOI中則是由
HSSFDataFormat來處理。為了能夠方便的獲得所需要的類型所對應的文本,我們可以使用HSSFCell.ToString()來處理。
於是剛才的代碼則變成了這樣:
switch(cell.CellType) { case HSSFCellType.BLANK: dr[i] = "[null]"; break; case HSSFCellType.BOOLEAN: dr[i] = cell.BooleanCellValue; break; case HSSFCellType.NUMERIC: dr[i] = cell.ToString(); break; case HSSFCellType.STRING: dr[i] = cell.StringCellValue; break; case HSSFCellType.ERROR: dr[i] = cell.ErrorCellValue; break; case HSSFCellType.FORMULA: default: dr[i] = "=" + cell.CellFormula; break; }