當你已經了解如何讀取 Excel,接下來最重要的是看懂程式碼。本篇將針對 C# 讀取 Excel 的完整範例進行解析,逐步說明 NPOI 程式碼的運作方式,幫助你真正理解每一段邏輯,而不是只會複製貼上。
開始範例程式碼解析
1 . 開啟 C# 讀取 Excel 教學|使用 NPOI 進行資料處理|C# Excel 系列 建立的程式

2 . 程式碼研究
我們找到button1按下會執行的程式碼,開始一行一行解讀。
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Excel Files|*.xlsx;*.xls";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
XSSFWorkbook workbook = new XSSFWorkbook(fs);
ISheet sheet = workbook.GetSheetAt(0);
for (int rowIndex = 0;rowIndex <= sheet.LastRowNum; rowIndex++)
{
IRow row = sheet.GetRow(rowIndex);
if (row != null)
{
for (int colIndex = 0;colIndex < row.LastCellNum; colIndex++)
{
ICell cell = row.GetCell(colIndex);
if (cell != null)
{
string cellValue = cell.ToString();
Console.WriteLine($"Row {rowIndex + 1},Column {colIndex + 1}: {cellValue}");
}
}
}
}
}
}
}
程式碼片段:
- OpenFileDialog openFileDialog = new OpenFileDialog();
- openFileDialog.Filter = "Excel Files|*.xlsx;*.xls";
- if (openFileDialog.ShowDialog() == DialogResult.OK)
- {
-------------------------------------------------------------------------------------------------------
1 、2 行是使用Windows Forms裡面自己內建的原件,先創建一個出來並且限制檔案只能選取Excel檔案,這個元件可以用來彈跳出一個選擇檔案的視窗。
第3行 執行ShowDialog()會把彈跳視窗叫出來,並且它會等待你選好檔案後按下開啟去執行第4行大括弧裡面的動作。如果把這個視窗關閉則這個元件就不會收到DialogResult.OK的訊號,就不會執行大括弧裡面的動作。
這段執行後就會如下圖跳出視窗。

(*補充: if 這是一個非常好用的語法,基本上它就是如字面上的意思一樣 "假設",假設條件成立就執行跟在if後面的大括號裡面的內容)
程式碼片段:
- string filePath = openFileDialog.FileName;
- using (FileStream fs = new FileStream(filePath,FileMode.Open, FileAccess.Read))
- {
-------------------------------------------------------------------------------------------------------
第 1 行 當彈跳視窗選完檔案按下開啟後,openFileDialog這個元件它裡面會有一個FileName儲存著你檔案的位置。我們就用一個字串型別(string)的變數(可以自己命名,但身為一個好的工程師會正確命名,所以我們叫這個變數為filePath)儲存這個檔案位置。
第 2 行 是固定的讀檔案格式,我們把filePath存的檔案位置丟到這個既定的讀檔案格式裡,電腦就會自動幫我們到那個位置讀取檔案,把檔案開啟後程式就會在第 3 行這個大括弧裡面做讀取檔案內容的操作。
(*補充: using 這個程式碼的功能,就是使用完後自動釋放資源。
例如:有時候我們有共用的Excel打開以後,Excel會跳出警告說有其他人開著,而這個using就是為了防止程式碼開啟檔案後沒有釋放掉資源,會造成其他人開啟或修改檔案時發生錯誤。
這只是一個防止資源被占用的用法,並不影響程式開發,以後看久了就會熟悉了,不必過於糾結。)
程式碼片段:
- XSSFWorkbook workbook = new XSSFWorkbook(fs);
- ISheet sheet = workbook.GetSheetAt(0);
-------------------------------------------------------------------------------------------------------
第 1 行 把讀到的檔案流 FileStream fs 放進來就能開始讀取裡面的內容。
第 2 行 我們先來讀取這個Excel的第一個工作表。如下圖紅框處這個就是Excel的工作表(Sheet)。workbook.GetSheetAt(0) 就如字面上的意思取得Excel的工作表(Sheet),0 代表取第一個工作表(Sheet)。

*補充:
如果我們有多個工作表,就可以用以下方法取得對應的其他工作表。
ISheet sheet1 = workbook.GetSheetAt(1);
ISheet sheet2 = workbook.GetSheetAt(2);
程式碼片段:
- for (int rowIndex = 0; rowIndex <= sheet.LastRowNum; rowIndex++)
- {
-------------------------------------------------------------------------------------------------------
第 1 行 這時我們要取得整個Sheet裡面的資料,所以我們要一列一列(Row)的讓程式去抓裡面的資料。這時候就要使用for迴圈,for迴圈有固定的格式。
在小括號內的第一個分號(;)前面的這段 int rowIndex = 0 就是要放你想要從數字幾開始,這裡我們希望從數字 0 開始,於是我們就自己命名一個 rowIndex 整數(int)型態的容器放0這個數字。
第二個分號(;)前面就是看你想讓這個迴圈重複跑多少次,我們要跑完整個Excel的資料,所以我們用前面取得的工作表(sheet)取得它的最後一行資料 LastRowNum,rowIndex <= sheet.LastRowNum 這裡程式就會開始判斷,因此 0 <= 9 條件成立,就會執行for迴圈大括弧裡面的程式。
第三個分號(;)前面就是執行完迴圈裡面的程式後,把rowIndex++ 這個就是+1的意思,所以rowIndex 會變成 1 ,並且繼續執行for迴圈的rowIndex <= sheet.LastRowNum判斷,直到rowIndex<= sheet.LastRowNum不成立就會停止執行這個迴圈。
*補充:(因為怕前面講會太複雜所以放到補充,看不懂沒關係以後就會慢慢懂)
(sheet.LastRowNum這個取出來的數字是9,因為套件設計者設計LastRowNum取得最後一個資料的位置,程式的起始位置是0開始算,所以10行資料的最後一筆位置就是9)
程式碼片段:
- IRow row = sheet.GetRow(rowIndex);
- if (row != null)
- {
-------------------------------------------------------------------------------------------------------
第 1 行 我們用工作表 sheet.GetRow(rowIndex) 照字面意思GetRow就是取得工作表的列(Row),並且使用我們剛剛for 迴圈裡面定義的 rowIndex 整數(int)型態容器指定要取得第幾列(Row),我們一開始指定 rowIndex = 0 所以就是從第一列開始取資料,會取得如下圖的紅框處資料表頭的部分。
之後隨著迴圈跑,rowIndex會改變。
rowIndex = 1、rowIndex = 2、rowIndex = 3 … rowIndex = 9。
就會去一列一列取得表身的資料。
第 2 - 3 行 則是判斷這列是不是空的,如不等於空(null) 則執行大括號裡面的程式。

程式碼片段:
- for (int colIndex = 0; colIndex < row.LastCellNum; colIndex++)
- {
-------------------------------------------------------------------------------------------------------
第 1-2 行 我們在前面取得列以後,要對每一個格子(cell)取出裡面的值,於是我們一樣使用for迴圈,指定一個名稱為 colIndex 的整數(int)容器並從 0 開始,然後我們要取到列裡面的最後一個格子的資料,所以就使用 row.LastCellNum,0 < 6 ,條件成立就執行迴圈裡面的程式碼,執行後colIndex++,直到colIndex =6 ,6 < 6 不成立才會跳出迴圈。
*補充:
(row.LastCellNum這個取出來的數字是6,因為套件設計者設計LastCellNum取得總共的格子數量並不是最後一格子的位置,所以依據我們範例的Excel資料總共有6個格子,因此會得到6不是5,跟LastRowNum不太一樣。)
程式碼片段:
- ICell cell = row.GetCell(colIndex);
- if (cell != null)
- {
- string cellValue = cell.ToString();
- Console.WriteLine($"Row {rowIndex + 1},Column {colIndex + 1}: {cellValue}");
- }
-------------------------------------------------------------------------------------------------------
第 1 行 我們用列(Row) row.GetCell(colIndex) 照字面意思GetCell就是取得列裡面的格子(cell)。
第 2 行 一樣判斷格子是不是空的,不等於空(null) 則執行大括號裡面的程式。
第 4 行 cell.ToString()是把取得的cell轉成字串的格式,然後放在一個名字為cellValue的字串容器。
第 5 行 Console.WriteLine()則是.net內建提供的功能,可以用來顯示容器裡面的值,讓資料視覺化方便檢查結果。原本範例程式碼想把顯示的結果用得漂亮一點,因此你會看到$"....." 這個一串複雜的文字,我建議直接改成Console.WriteLine(cellValue); 只顯示格子裡面的值不顯示其他多餘的東西,後續對程式熟悉了再來了解範例的用法。
這些程式碼執行後會根據sheet裡面有幾列(Row)然後一列一列的執行迴圈,再對每一列的裡面有幾個格子(cell)一個一個的執行迴圈。最後再輸出的地方就會開始一個一個的顯示cell裡面的值。
依序顯示 : 生產日期、出貨日期、貨品名稱、出貨數量、貨品價格、生產人員、20250901…一直到最後一個John顯示後,程式才會停止。

結論
到這裡我們已經對於讀取Excel的基本應用有了了解,離軟體工程師又更近了一大步!下一章我們就可以進階針對需求微調程式來符合使用者讀Excel的真正需求。














