每一個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;
}