寫C#已經有一段時間,也練習了不少把程式模組化的設計方式,今天來分享一段最近寫的,用NPOI來把DataSet物件轉出單個Excel的方法,目前適用在Windows Form的畫面使用,這是從個人使用的模組內挖出來的,由於程式內都已特意寫好註解,就把整段貼上來吧。
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using Microsoft.IdentityModel.Tokens;
using System.Data;
using System.Reflection;
using System.Collections;
using System.ComponentModel.DataAnnotations;
namespace Modules
{
public class Npoi
{
public string ExpFilename = "ExcelExport" + DateTime.Now.ToString("-yyMMdd_HHmm")+".xlsx";
public Npoi()
{
}
/// <summary>
/// 將資料設定為資料表集合後 轉出成Excel檔案
/// </summary>
/// <param name="Ds">資料表的集合</param>
/// <param name="filename">檔案名稱</param>
/// <param name="Args">活頁簿參數 </param>
/// 假設 Ds.Tables 資料表數量 n
/// Args 參數數量 0 : 以檔案名稱擴充 1.活頁簿名稱 2.標題
/// Args 參數數量 n : 以單一參數擴充 1.活頁簿名稱 2.標題
/// Args 參數數量 n*2 : 以參數對應 1.活頁簿名稱 2.標題 3.次標題(由標題擴充)
/// Args 參數數量 n*3 : 以參數對應 1.活頁簿名稱 2.標題 3.次標題
/// <returns>
/// 資料表為空或零時 回應 -1 / 其餘則 回應 資料表數量 n
/// </returns>
public int ExportExcelFile(DataSet Ds, string filename, string[] Args)
{
if (!filename.IsNullOrEmpty())
ExpFilename = filename + DateTime.Now.ToString("-yyMMdd_HHmm") + ".xlsx";
if (Ds.Tables.Count == 0)
return -1;
int ArgTbCt = Args.Length / Ds.Tables.Count;
DateTime progTime = DateTime.Now;
// 建立試算表
XSSFWorkbook xSSFWorkbook = new XSSFWorkbook();
ICellStyle cellStyle = xSSFWorkbook.CreateCellStyle(); //首先建單元格格式
// 引用格式建立物件
XSSFDataFormat ft = (XSSFDataFormat)xSSFWorkbook.CreateDataFormat();
// 粗體字設定
XSSFFont f_bold = (XSSFFont)xSSFWorkbook.CreateFont();
f_bold.IsBold = true;
// 數字格式
XSSFCellStyle st_Num = (XSSFCellStyle)xSSFWorkbook.CreateCellStyle();
st_Num.DataFormat = ft.GetFormat("###,##0");
// 置中格式
XSSFCellStyle st_Cen = (XSSFCellStyle)xSSFWorkbook.CreateCellStyle();
st_Cen.Alignment = HorizontalAlignment.Center;
st_Cen.VerticalAlignment = VerticalAlignment.Center;
// 粗體字
XSSFCellStyle f_b = (XSSFCellStyle)xSSFWorkbook.CreateCellStyle();
f_b.SetFont(f_bold);
// 置中粗體格式
XSSFCellStyle st_f_b_Cen = (XSSFCellStyle)xSSFWorkbook.CreateCellStyle();
st_f_b_Cen.Alignment = HorizontalAlignment.Center;
st_f_b_Cen.VerticalAlignment = VerticalAlignment.Center;
st_f_b_Cen.SetFont(f_bold);
//粗體的數字
XSSFCellStyle st_N_f_B = (XSSFCellStyle)xSSFWorkbook.CreateCellStyle();
st_N_f_B.SetFont(f_bold);
st_N_f_B.DataFormat = ft.GetFormat("###,##0");
// 處理檔案名稱與活頁簿名稱
for (int i = 0; i < Ds.Tables.Count; i++)
{
DataTable Dt = Ds.Tables[i];
string sheet_name = "", sheet_title = "", sheet_subtitle = "";
// 偵測 字串陣列 / 資料表
switch (ArgTbCt)
{
// 一樣多
case 1:
sheet_name = Args[i] + i.ToString("_00");
sheet_title = Args[i];
sheet_subtitle = "";
break;
// 兩倍
case 2:
sheet_name = Args[i * ArgTbCt] + i.ToString("_00");
sheet_title = Args[i * ArgTbCt + 1];
sheet_subtitle = Args[i * ArgTbCt + 1];
break;
case 3:
sheet_name = Args[i * ArgTbCt] + i.ToString("_00");
sheet_title = Args[i * ArgTbCt + 1];
sheet_subtitle = Args[i * ArgTbCt + 2];
break;
// 為零時
default:
sheet_name = ExpFilename.Replace(".xlsx", "") + i.ToString("_00");
sheet_title = ExpFilename.Replace(".xlsx", "") + i.ToString("_00") + "_sheet";
sheet_subtitle = "";
break;
}
int c_ct = Dt.Columns.Count;
// 建立工作表物件
ISheet sheet = xSSFWorkbook.CreateSheet(sheet_name);
// 第0列
IRow rows = sheet.CreateRow(0);
rows.CreateCell(0).SetCellValue(sheet_title);
sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, c_ct - 1));
sheet.GetRow(0).GetCell(0).CellStyle = st_f_b_Cen;
// 第1列
rows = sheet.CreateRow(1);
rows.CreateCell(0).SetCellValue(sheet_subtitle);
sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 1, 0, c_ct - 1));
sheet.GetRow(1).GetCell(0).CellStyle = st_Cen;
// 自第三列開始 向下寫 先寫入欄位名稱
rows = sheet.CreateRow(3);
for (int j = 0; j < Dt.Columns.Count; j++)
{
rows.CreateCell(j).SetCellValue(Dt.Columns[j].ColumnName);
sheet.GetRow(3).GetCell(j).CellStyle = f_b;
}
// 使用雙迴圈自第四列往下寫入各欄位
int m = 0;
for (int j = 0; j < Dt.Rows.Count; j++)
{
rows = sheet.CreateRow(j + 4);
for (int k = 0; k < Dt.Columns.Count; k++)
{
//判斷內容是數字或文字 指定不同寫入方法
if ( IsNumType(Dt.Columns[k].DataType) )
{
rows.CreateCell(k).SetCellValue(Convert.ToDouble(Dt.Rows[j][k].ToString()!.Replace(" ", "")));
}
else
{
rows.CreateCell(k).SetCellValue(Dt.Rows[j][k].ToString()!.Replace(" ", ""));
}
m = j + 5;
}
}
TimeSpan ts = DateTime.Now - progTime;
rows.CreateCell(Dt.Columns.Count).SetCellValue(ts.Milliseconds);
}
FileStream streamWriter = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + ExpFilename, FileMode.Create, FileAccess.ReadWrite);
// 把活頁簿物件寫入檔案
xSSFWorkbook.Write(streamWriter);
streamWriter.Close();
streamWriter.Dispose();
return Ds.Tables.Count;
}
private bool IsNumType(Type type)
{
bool IsNum = true;
if (type == typeof(String)) { IsNum = false; }
if (type == typeof(TimeSpan)) { IsNum = false; }
return IsNum;
}
/// <summary>
/// 送入物件的類別是否為數字的判定
/// </summary>
/// <param name="sender"></param>
/// <returns>數字為真,非數字返回否。</returns>
private bool IsNum(object sender)
{
bool IsNum = false;
IsNum = Decimal.TryParse((string)sender, out decimal tryit);
return IsNum;
}
}
}