以DataSet物件配合文字陣列輸出單個檔多工作表的Excel活頁簿檔案

  • 80
  • 0
  • C#
  • 2023-11-03

寫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("&nbsp;", "")));
                	}
                	else
                	{
                    	rows.CreateCell(k).SetCellValue(Dt.Rows[j][k].ToString()!.Replace("&nbsp;", ""));
                	}
                	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;
	}
  }
}
iT邦幫忙 個人帳號:Kw6732