如果只是要純粹將陣列內容輸出成 Excel 能讀的檔案,那直接參考 使用 C# 將資料匯出為 CSV 中的方法三就可以快速達成。但因為 CSV 檔案僅透過逗號與分行組成,當資料內容含有特殊符號時會發生錯誤,且後續不能進行圖表繪製與使用其他 Excel 功能,對於複雜資料和資料分析等需求來說,僅使用 CSV 無法滿足要求。
C# 是基於 .NET 框架的程式語言,對於處理 Excel 檔案部分,目前於市面上有付費的 Spire.XLS、.NET Excel Framework 與開源免費的 NPOI。在這篇文章中,我們將要透過 Visual Studio 來使用 NPOI 套件,將結構陣列輸出至 Excel 檔案。
安裝
首先我們要用 NuGet 來為專案安裝 NPOI 套件,打開你的專案後,從頂部導覽列的工具,進入 NuGet 套件管理員 > 管理方案的 NuGet 套件。
接下來直接搜尋 NPOI,找到下圖中最高下載數且作者是 NPOI Contributors 的套件並安裝。不要安裝到 DotNetCore.NPOI,據作者所說,DotNetCore.NPOI 是中國 NCC (China .NET Core Community) 所為,詳細資訊可參考中文翻譯版 Dotnetcore.NPOI项目的真相 或英文原文 The real history of Dotnetcore.NPOI。
新增引用
開始撰寫主要功能前,必須先引用 NPOI 命名空間。請在原始碼檔案最前面加入以下引用。
using NPOI.XSSF.UserModel;
撰寫功能
緊接著要來開始撰寫主要的程式功能,主要流程如下:
為了程式的擴充性,在建立標題與寫入資料時我會使用 Reflection 的方式來取得結構中的屬性名稱與值,後續可以把此段程式碼改寫成泛型類別,一勞永逸。如果你目前只是要一個簡單的資料輸出的話,也可以於建立標題與寫入資料時直接指定屬性。
建立假資料
我們先定義 Wave 結構作為範例。其中有皆為整數型別的 Id 與 Value 屬性,後續我們還可以沿用此結構來繪製圖表。
struct Wave
{
public int Id { get; set; }
public int Value { get; set; }
public Wave(int id, int value)
{
Id = id;
Value = value;
}
}
接下來建立 Wave 陣列並填入有序的 Id 與範圍 1~100 內的隨機 Value。
var waves = new Wave[100];
for (int i = 0; i < 100; i++)
{
waves[i] = new Wave(i + 1, new Random().Next(0, 100));
}
建立活頁簿與工作表
再來的內容就跟我們實際操作 Excel 軟體一樣,先建立活頁簿檔案,再新增與命名工作表。工作表能建立多個,可自行用變數儲存起來。
var workbook = new XSSFWorkbook();
var sheet = workbook.CreateSheet("A Wave List");
建立標題
進入重點,首先透過 Type.GetProperties 與 Linq 將結構的屬性名稱提取出來,並將它們插入至工作表的第 0 行中。
詳細的 Reflection 用法可以參考 Type.GetProperties 方法 (System) 與 PropertyInfo 類別 (System.Reflection) 的範例程式。
var propertyNames = typeof(Wave).GetProperties().Select(x => x.Name).ToArray();
var header = sheet.CreateRow(0);
for (int i = 0; i < propertyNames.Length; i++)
{
header.CreateCell(i).SetCellValue(propertyNames[i]);
}
寫入資料
我們用雙迴圈來新增資料列,注意這裡的 CreateRow 內的數字不能跟標題列 (Index = 0) 重複,否則資料會被覆蓋。
第二層迴圈一樣使用 Reflection 的方式提取屬性值,並寫入當前的資料列中。這邊我用了 Convert.ToInt32 方法,是因為我確定我的資料都是整數值,如果你的資料是其他型別的話,可能就要另外去設計 Attribute 來保持其可擴充性,可參考 Attribute 類別 (System)。
for (int i = 0; i < waves.Length; i++)
{
var row = sheet.CreateRow(i + 1);
for (int j = 0; j < propertyNames.Length; j++)
{
var value = typeof(Wave).GetProperty(propertyNames[j]).GetValue(waves[i]);
row.CreateCell(j).SetCellValue(Convert.ToInt32(value));
}
}
存檔輸出
最後即是存檔輸出,這邊用最簡單的 File.Create 建立一個 .xlsx 檔案,再用 NPOI 活頁簿內建的 Write 方法來寫入。
建置專案並執行後,我們就可以在與執行檔相同的資料夾中找到輸出的 Excel 檔案,大功告成!
using (var fileStream = File.Create($"{DateTime.Now.ToString("HHmmss")}.xlsx"))
{
workbook.Write(fileStream);
}
參考資料
C# 映射(Reflection) 基本用法 | Ben Huang’s Blog - 點部落 (dotblogs.com.tw)
PropertyInfo.GetValue 方法 (System.Reflection) | Microsoft Learn
nissl-lab/npoi-examples: To get started with NPOI, here is all the official examples. (github.com)
Free .NET Excel API - Developing Excel in C#, VB.NET, ASP.NET (e-iceblue.com)