NPOI之所以強大,並不是因為它支持導出Excel,而是因為它支持導入Excel ,並能“理解”OLE2文檔結構,這也是其他一些Excel讀寫庫比較弱的方面。通 常,讀入並理解結構遠比導出來得復雜,因為導入你必須假設一切情況都是可能 的,而生成你只要保證滿足你自己需求就可以了,如果把導入需求和生成需求比 做兩個集合,那麼生成需求通常都是導入需求的子集,這一規律不僅體現在 Excel讀寫庫中,也體現在pdf讀寫庫中,目前市面上大部分的 pdf庫僅支持生成 ,不支持導入。
如果你不相信NPOI能夠很好的理解OLE2文檔格式,那就去下載POIFS Brower 。具體可以參考這篇文章的介紹:Office文件格式解惑。當然單單理解OLE2是不 夠的,因為Excel文件格式是BIFF,但BIFF是以OLE2為基礎的,做個很形象的比 喻就是:OLE2相當於磁盤的FAT格式,BIFF相當於文件和文件夾。NPOI負責理解 BIFF格式的代碼基本都在HSSF命名空間裡面。
好了,剛才廢話了一會兒,主要是給大家打打基礎,現在進入正題。
本文將以DataTable為容器讀入某xls的第一個工作表的數據(最近群裡面很 多人問這個問題)。
在開始之前,我們先來補些基礎知識。每一個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(養成好習慣,呵呵)。
HSSFWorkbook hssfworkbook;
void InitializeWorkbook(string path)
{
//read the template via FileStream, it is suggested to use FileAccess.Read to prevent file lock.
//book1.xls is an Excel-2007-generated file, so some new unknown BIFF records are added.
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
{
hssfworkbook = new HSSFWorkbook(file);
}
}
接下來我們要開始寫最重要的函數ConvertToDataTable,即把HSSF的數據放 到一個DataTable中。
HSSFSheet sheet = hssfworkbook.GetSheetAt(0);
System.Collections.IEnumerator rows = sheet.GetRowEnumerator ();
while (rows.MoveNext())
{
HSSFRow row = (HSSFRow)rows.Current;
//TODO::Create DataTable row
for (int i = 0; i < row.LastCellNum; i++)
{
HSSFCell cell = row.GetCell(i);
//TODO::set cell value to the cell of DataTables
}
上面的結構大家都應該能看懂吧,無非就是先遍歷行,再遍歷行中的每一列 。這裡引出了一個難點,由於Excel的單元格有好幾種類型,類型不同顯示的東 西就不同,具體的類型有 布爾型、數值型、文本型、公式型、空白、錯誤。
public enum HSSFCellType
{
Unknown = -1,
NUMERIC = 0,
STRING = 1,
FORMULA = 2,
BLANK = 3,
BOOLEAN = 4,
ERROR = 5,
}
這裡的HSSFCellType描述了所有的類型,但細心的朋友可能已經發現了,這 裡沒有日期型,這是為什麼呢?這是因為Excel底層並沒有一定日期型,而是通 過數值型來替代,至於如何區分日期和數字,都是由文本顯示的樣式決定的,在 NPOI中則是由HSSFDataFormat來處理。為了能夠方便的獲得所需要的類型所對應 的文本,我們可以使用HSSFCell.ToString()來處理。
於是剛才的代碼則變成了這樣:
HSSFSheet sheet = hssfworkbook.GetSheetAt(0);
System.Collections.IEnumerator rows = sheet.GetRowEnumerator ();
DataTable dt = new DataTable();
for (int j = 0; j < 5; j++)
{
dt.Columns.Add(Convert.ToChar(((int)'A')+j).ToString());
}
while (rows.MoveNext())
{
HSSFRow row = (HSSFRow)rows.Current;
DataRow dr = dt.NewRow();
for (int i = 0; i < row.LastCellNum; i++)
{
HSSFCell cell = row.GetCell(i);
if (cell == null)
{
dr[i] = null;
}
else
{
dr[i] = cell.ToString();
}
}
dt.Rows.Add(dr);
}
是不是很簡單,呵呵!
當然,如果你要對某個特定的單元格類型做特殊處理,可以通過判 HSSFCell.CellType來解決,比如下面的代碼:
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(); //This is a trick to get the correct value of the cell. NumericCellValue will return a numeric value no matter the cell value is a date or a number.
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;
}
這裡只是舉個簡單的例子。
原文地址: http://www.cnblogs.com//archive/2009/12/25/1631075.html