使用NPOI获取Excel表格数据
每一个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; }