C# net8使用NPOI匯出多個sheet工作簿的execl檔案

ziff123發表於2024-12-09

1、安裝NPOI 2.7.2

2、工具類DataTableTool.cs,將list 轉成DataTable

C# net8使用NPOI匯出多個sheet工作簿的execl檔案
using System.Collections;
using System.Data;
using System.Reflection;

namespace Common.Helper
{
    public static class DataTableTool
    {
        /// <summary>    
        /// 轉化一個DataTable    
        /// </summary>    
        /// <typeparam name="T"></typeparam>    
        /// <param name="list"></param>    
        /// <returns></returns>    
        public static DataTable ToDataTable<T>(this IEnumerable<T> list)
        {

            //建立屬性的集合    
            List<PropertyInfo> pList = new List<PropertyInfo>();
            //獲得反射的入口    

            Type type = typeof(T);
            DataTable dt = new DataTable();
            //把所有的public屬性加入到集合 並新增DataTable的列    
            Array.ForEach<PropertyInfo>(type.GetProperties(), p => { pList.Add(p); dt.Columns.Add(p.Name, p.PropertyType); });
            foreach (var item in list)
            {
                //建立一個DataRow例項    
                DataRow row = dt.NewRow();
                //給row 賦值    
                pList.ForEach(p => row[p.Name] = p.GetValue(item, null));
                //加入到DataTable    
                dt.Rows.Add(row);
            }
            return dt;
        }


        /// <summary>    
        /// DataTable 轉換為List 集合    
        /// </summary>    
        /// <typeparam name="TResult">型別</typeparam>    
        /// <param name="dt">DataTable</param>    
        /// <returns></returns>    
        public static List<T> ToList<T>(this DataTable dt) where T : class, new()
        {
            //建立一個屬性的列表    
            List<PropertyInfo> prlist = new List<PropertyInfo>();
            //獲取TResult的型別例項  反射的入口    

            Type t = typeof(T);

            //獲得TResult 的所有的Public 屬性 並找出TResult屬性和DataTable的列名稱相同的屬性(PropertyInfo) 並加入到屬性列表     
            Array.ForEach<PropertyInfo>(t.GetProperties(), p => { if (dt.Columns.IndexOf(p.Name) != -1) prlist.Add(p); });

            //建立返回的集合    

            List<T> oblist = new List<T>();

            foreach (DataRow row in dt.Rows)
            {
                //建立TResult的例項    
                T ob = new T();
                //找到對應的資料  並賦值    
                prlist.ForEach(p => { if (row[p.Name] != DBNull.Value) p.SetValue(ob, row[p.Name], null); });
                //放入到返回的集合中.    
                oblist.Add(ob);
            }
            return oblist;
        }




        /// <summary>    
        /// 將集合類轉換成DataTable    
        /// </summary>    
        /// <param name="list">集合</param>    
        /// <returns></returns>    
        public static DataTable ToDataTableTow(IList list)
        {
            DataTable result = new DataTable();
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();

                foreach (PropertyInfo pi in propertys)
                {
                    Type colType = pi.PropertyType;
                    if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        colType = colType.GetGenericArguments()[0];
                    }
                    result.Columns.Add(pi.Name, colType);
                }
                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        object obj = pi.GetValue(list[i], null);
                        tempList.Add(obj);
                    }
                    object[] array = tempList.ToArray();
                    result.LoadDataRow(array, true);
                }
            }
            return result;
        }


        /// <summary>    
        /// 將泛型集合類轉換成DataTable    
        /// </summary>    
        /// <typeparam name="T">集合項型別</typeparam>    
        /// <param name="list">集合</param>    
        /// <returns>資料集(表)</returns>    
        public static DataTable ToDataTable<T>(IList<T> list)
        {
            return ToDataTable<T>(list, null);

        }

        /// <summary>    
        /// 將泛型集合類轉換成DataTable    
        /// </summary>    
        /// <typeparam name="T">集合項型別</typeparam>    
        /// <param name="list">集合</param>    
        /// <param name="propertyName">需要返回的列的列名</param>    
        /// <returns>資料集(表)</returns>    
        public static DataTable ToDataTable<T>(IList<T> list, params string[] propertyName)
        {
            List<string> propertyNameList = new List<string>();
            if (propertyName != null)
                propertyNameList.AddRange(propertyName);
            DataTable result = new DataTable();
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    if (propertyNameList.Count == 0)
                    {
                        result.Columns.Add(pi.Name, pi.PropertyType);
                    }
                    else
                    {
                        if (propertyNameList.Contains(pi.Name))
                            result.Columns.Add(pi.Name, pi.PropertyType);
                    }
                }

                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        if (propertyNameList.Count == 0)
                        {
                            object obj = pi.GetValue(list[i], null);
                            tempList.Add(obj);
                        }
                        else
                        {
                            if (propertyNameList.Contains(pi.Name))
                            {
                                object obj = pi.GetValue(list[i], null);
                                tempList.Add(obj);
                            }
                        }
                    }
                    object[] array = tempList.ToArray();
                    result.LoadDataRow(array, true);
                }
            }
            return result;
        }
    }
}
View Code

3、execl生成類ExcelTool.cs

C# net8使用NPOI匯出多個sheet工作簿的execl檔案
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System.Data;

namespace Common.Helper
{
    public static class ExcelTool
    {  /// <summary>
       /// 將excel中的資料匯入到DataTable中
       /// </summary>
       /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
       /// <param name="fileName">檔名稱</param>
       /// <param name="sheetName">excel工作薄sheet的名稱</param>
       /// <returns>返回的DataTable</returns>
        public static DataTable ExcelStreamToDataTable(bool isFirstRowColumn, string fileName, Stream fs, string sheetName = "")
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(fileName);
            }
            var data = new DataTable();
            IWorkbook workbook = null;
            try
            {
                if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
                {
                    workbook = new XSSFWorkbook(fs);
                }
                else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
                {
                    workbook = new HSSFWorkbook(fs);
                }

                ISheet sheet = null;
                if (workbook != null)
                {
                    //如果沒有找到指定的sheetName對應的sheet,則嘗試獲取第一個sheet
                    if (sheetName == "")
                    {
                        sheet = workbook.GetSheetAt(0);
                    }
                    else
                    {
                        sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0);
                    }

                }
                if (sheet == null) return data;
                var firstRow = sheet.GetRow(0);
                //一行最後一個cell的編號 即總的列數
                int cellCount = firstRow.LastCellNum;
                int startRow;
                if (isFirstRowColumn)
                {
                    for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
                    {
                        var cell = firstRow.GetCell(i);
                        var cellValue = cell.ToString();
                        if (cellValue == null) continue;
                        var column = new DataColumn(cellValue);
                        data.Columns.Add(column);
                    }
                    startRow = sheet.FirstRowNum + 1;
                }
                else
                {
                    startRow = sheet.FirstRowNum;
                }
                //最後一列的標號
                var rowCount = sheet.LastRowNum;
                for (var i = startRow; i <= rowCount; ++i)
                {
                    var row = sheet.GetRow(i);
                    //沒有資料的行預設是null
                    if (row == null) continue;
                    var dataRow = data.NewRow();
                    for (int j = row.FirstCellNum; j < cellCount; ++j)
                    {
                        //同理,沒有資料的單元格都預設是null
                        if (row.GetCell(j) != null)
                            dataRow[j] = row.GetCell(j).ToString();
                    }
                    data.Rows.Add(dataRow);
                }

                return data;
            }
            catch (IOException ioex)
            {
                throw new IOException(ioex.Message);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }


        /// <summary>
        /// 將excel中的資料匯入到DataTable中
        /// </summary>
        /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
        /// <param name="fileName">檔案路徑</param>
        /// <param name="sheetName">excel工作薄sheet的名稱</param>
        /// <returns>返回的DataTable</returns>
        public static DataTable ExcelToDataTable(bool isFirstRowColumn, string fileName, string sheetName = "")
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(fileName);
            }
            var data = new DataTable();
            IWorkbook workbook = null;
            FileStream fs = null;
            try
            {
                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
                {
                    workbook = new XSSFWorkbook(fs);
                }
                else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
                {
                    workbook = new HSSFWorkbook(fs);
                }

                ISheet sheet = null;
                if (workbook != null)
                {
                    //如果沒有找到指定的sheetName對應的sheet,則嘗試獲取第一個sheet
                    if (sheetName == "")
                    {
                        sheet = workbook.GetSheetAt(0);
                    }
                    else
                    {
                        sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0);
                    }
                }
                if (sheet == null) return data;
                var firstRow = sheet.GetRow(0);
                //一行最後一個cell的編號 即總的列數
                int cellCount = firstRow.LastCellNum;
                int startRow;
                if (isFirstRowColumn)
                {
                    for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
                    {
                        var cell = firstRow.GetCell(i);
                        var cellValue = cell.StringCellValue;
                        if (cellValue == null) continue;
                        var column = new DataColumn(cellValue);
                        data.Columns.Add(column);
                    }
                    startRow = sheet.FirstRowNum + 1;
                }
                else
                {
                    startRow = sheet.FirstRowNum;
                }
                //最後一列的標號
                var rowCount = sheet.LastRowNum;
                for (var i = startRow; i <= rowCount; ++i)
                {
                    var row = sheet.GetRow(i);
                    //沒有資料的行預設是null
                    if (row == null) continue;
                    var dataRow = data.NewRow();
                    for (int j = row.FirstCellNum; j < cellCount; ++j)
                    {
                        //同理,沒有資料的單元格都預設是null
                        if (row.GetCell(j) != null)
                            dataRow[j] = row.GetCell(j).ToString();
                    }
                    data.Rows.Add(dataRow);
                }

                return data;
            }
            catch (IOException ioex)
            {
                throw new IOException(ioex.Message);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }
        /// <summary>
        /// 將DataTable資料匯入到excel中
        /// </summary>
        /// <param name="data">要匯入的資料</param>
        /// <param name="isColumnWritten">DataTable的列名是否要匯入</param>
        /// <param name="sheetName">要匯入的excel的sheet的名稱</param>
        /// <param name="fileName">資料夾路徑</param>
        /// <returns>匯入資料行數(包含列名那一行)</returns>
        public static int DataTableToExcel(DataTable[] dataArr, string[] sheetNameArr, bool isColumnWritten, string fileName)
        {
            if (dataArr == null)
            {
                throw new ArgumentNullException("data");
            }
            if (dataArr.Length != sheetNameArr.Length)
            {
                throw new ArgumentNullException("data長度與sheetName不一致");
            }
           
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(fileName);
            }
            IWorkbook workbook = null;
            if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0)
            {
                workbook = new XSSFWorkbook();
            }
            else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0)
            {
                workbook = new HSSFWorkbook();
            }

            FileStream fs = null;
            try
            {
                fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                ISheet[] sheetArr = new ISheet[sheetNameArr.Length];
                for(int n= 0; n < sheetArr.Length; n++)
                {
                        sheetArr[n] = workbook.CreateSheet(sheetNameArr[n]);
                }
                
                var cellStyle = workbook.CreateCellStyle();
                cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("@");

                //  var cellStyle1 = workbook.CreateCellStyle();
                // cellStyle1.DataFormat = HSSFDataFormat.GetBuiltinFormat("yyyy年m月d日");
                var cellStyle1 = workbook.CreateCellStyle();
                var format = workbook.CreateDataFormat();
                cellStyle1.DataFormat = (format.GetFormat("yyyy-mm-dd"));
                //   cell.setCellStyle(cellStyle);


                int j;
                int count = 0 ;
                //寫入DataTable的列名,寫入單元格中
                for(int m = 0; m < sheetArr.Length; m++)
                {
                    var sheet = sheetArr[m];
                    DataTable data = dataArr[m];
                    if (isColumnWritten)
                    {
                        var row = sheet.CreateRow(0);
                        for (j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);

                            Type types = data.Columns[j].DataType;
                            if (types.Name == "DateTime")
                            {
                                sheet.SetDefaultColumnStyle(j, cellStyle1);
                            }
                            else
                            {
                                sheet.SetDefaultColumnStyle(j, cellStyle);
                            }
                        }
                        count = 1;
                    }
                    else
                    {
                        count = 0;
                    }
                    //遍歷迴圈datatable具體資料項
                    int i;
                    for (i = 0; i < data.Rows.Count; ++i)
                    {
                        var row = sheet.CreateRow(count);
                        for (j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
                        }
                        ++count;
                    }
                }
                
                //將檔案流寫入到excel
                workbook.Write(fs);
                return count;
            }
            catch (IOException ioex)
            {
                throw new IOException(ioex.Message);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }
    }
}
View Code

4、使用

        [HttpGet]
        public async Task<MessageModel<string>> ExportExcel(string key = "",  int orderBy = 0)
        {
            try
            {
                string fileName = $"{DateTime.Now.ToString("yyyyMMdd_HHmss")}_{_user.ShopID}" + ".xlsx";
                string folder = $"execl\\shopbak";
                string urlFolder = $"execl/shopbak";
                string folderpath = Path.Combine($"{_env.WebRootPath}\\{folder}\\");
                string path = folderpath + fileName;

                if (!Directory.Exists(folderpath))
                {
                    Directory.CreateDirectory(folderpath);
                }
                //刪除舊檔案
                foreach (string file in Directory.GetFiles(folderpath))
                {
                    try
                    {
                        FileInfo fileInfo = new FileInfo(file);
                        DateTime localCreationTime = fileInfo.CreationTime; // 獲取檔案的本地建立時間
                        Console.WriteLine("檔案建立時間(本地): " + localCreationTime.ToString());
                        //建立時間與當前時間比較,相差30秒以上則刪除
                        if (DateTime.Now.Subtract(localCreationTime).TotalSeconds > 60)
                        {
                            System.IO.File.Delete(file);
                        }
                    }
                    catch(Exception ex)
                    {
                        _logger.LogError("刪除檔案失敗" + ex);
                    }
                }
                DataTable[] dtArr = new DataTable[2];
                string[] sheetNameArr = { "全部會員", "次卡會員"};

                #region 全部會員
                var result = await Get(page: 1, intPageSize: 5000, key: key, memberType: 0, orderBy: orderBy);  //獲取資料
                if (!result.success)
                {
                    return Failed("查詢資料失敗");
                }
                var list = result.response.data.Select(s => new {
                    s.Name,
                    s.Phone,
                    s.Points,
                    s.Birthday,
                    s.Sex,
                    s.CardNO,
                    s.Detail,
                    s.StoreCardName,
                    s.StoreCardBalance,
                    s.CreateTime
                });
                DataTable dt = DataTableTool.ToDataTableTow(list.ToList());
                dt.Columns["Name"].ColumnName = "名字";
                dt.Columns["Phone"].ColumnName = "手機";
                dt.Columns["Points"].ColumnName = "積分";
                dt.Columns["Birthday"].ColumnName = "生日";
                dt.Columns["Sex"].ColumnName = "性別";
                dt.Columns["CardNO"].ColumnName = "會員卡號";
                dt.Columns["Detail"].ColumnName = "詳情";
                dt.Columns["StoreCardName"].ColumnName = "儲值卡";
                dt.Columns["StoreCardBalance"].ColumnName = "儲值卡餘額";
                dt.Columns["CreateTime"].ColumnName = "新增時間";

                dtArr[0] = dt;
                #endregion

                #region 次卡
                var timesResult = await Get(page: 1, intPageSize: 5000, key: key, memberType: 1, orderBy: orderBy);
                if (!timesResult.success)
                {
                    return Failed("查詢資料失敗");
                }
                var timesList = timesResult.response.data.Select(s => new {
                    s.Name,
                    s.Phone,
                    s.Points,
                    s.Birthday,
                    s.Sex,
                    s.CardNO,
                    s.Detail,
                    s.TimesCardName,
                    s.TimesBusinessName,
                    s.TimesCardRemainCount,
                    s.CreateTime
                });
                DataTable timesDT = DataTableTool.ToDataTableTow(timesList.ToList());
                timesDT.Columns["Name"].ColumnName = "名字";
                timesDT.Columns["Phone"].ColumnName = "手機";
                timesDT.Columns["Points"].ColumnName = "積分";
                timesDT.Columns["Birthday"].ColumnName = "生日";
                timesDT.Columns["Sex"].ColumnName = "性別";
                timesDT.Columns["CardNO"].ColumnName = "會員卡號";
                timesDT.Columns["Detail"].ColumnName = "詳情";
                timesDT.Columns["TimesCardName"].ColumnName = "次卡";
                timesDT.Columns["TimesBusinessName"].ColumnName = "次卡專案";
                timesDT.Columns["TimesCardRemainCount"].ColumnName = "剩餘次數";
                timesDT.Columns["CreateTime"].ColumnName = "新增時間";

                dtArr[1] = timesDT;

                #endregion


                int count = ExcelTool.DataTableToExcel(dtArr, sheetNameArr, true, path);

                if (System.IO.File.Exists(path))
                {
                    var imgUrl = $"{Request.Scheme}://{Request.Host}/{urlFolder}/{fileName}";
                    return Success(imgUrl, "成功");
                }
                return Failed("匯出失敗");
            }
            catch(Exception ex)
            {
                _logger.LogError("匯出execl異常" + ex);
                return Failed("異常");
            }
        }

相關文章