直接貼代碼:
using DongYang.Core.Model.Domain; using DongYang.Core.Utils; using NLog; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.IO; using System.Threading; namespace DongYang.Core.Service { public class DYTrackANODetail700013TodayNewService { private readonly Logger _logger = LogManager.GetCurrentClassLogger();//日志組件 /// <summary> /// 導出excel /// </summary> /// <param name="anomateexcels"></param> /// <param name="currentTime"></param> public void ExportToExcel(List<Anomateexcel> anomateexcels, DateTime currentTime) { Stopwatch sw = new Stopwatch(); sw.Start(); FileStream file = null; string strBeginTime = string.Empty;//查詢開始時間 string strEndTime = string.Empty;//查詢結束時間 try { //模板文件 string templateFileName = AppDomain.CurrentDomain.BaseDirectory + "\\template.xlsx"; //導出文件 string reportFileName = FileHelper.GetExportFilePath(currentTime) + $"\\{currentTime.ToString("yyyyMMdd_HHmmss")}.xlsx"; //獲取查詢日期 this.GetTime(currentTime, out strBeginTime, out strEndTime); //查詢數據總數 int count = this.GetDataTableCount(strBeginTime, strEndTime); if (count == 0) return; //先拷貝空文件 File.Copy(templateFileName, reportFileName); //分頁查詢數據,在循環里面,打開拷貝的文件並追加數據,最后關閉文件句柄 var pages = Math.Ceiling(Convert.ToDouble(count) / ConfigHelper.PageSize); for (int pageIndex = 1; pageIndex <= pages; pageIndex++) { var startRow = (pageIndex - 1) * ConfigHelper.PageSize + 1; var endRow = pageIndex * ConfigHelper.PageSize; var dt = this.GetDataTable(strBeginTime, strEndTime, startRow, endRow); file = new FileStream(reportFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); XSSFWorkbook xssfworkbook = new XSSFWorkbook(file);//將文件讀到內存,在內存中操作excel file.Close(); XSSFSheet xssfsheet = xssfworkbook.GetSheet(ConfigHelper.WorkSheetName) as XSSFSheet; var beginRow = 3 + startRow - 1;//這里的beginRow這么處理,是因為我的Excel標題是在第三行 for (var i = 0; i < dt.Rows.Count; i++) { var excelRow = xssfsheet.CreateRow(beginRow++); foreach (var anomateexcel in anomateexcels) { var excelCell = excelRow.CreateCell(anomateexcel.Excellist.ToInt()); excelCell.SetCellType(NPOI.SS.UserModel.CellType.String); var value = dt.Rows[i][anomateexcel.Anofield].ToString(); excelCell.SetCellValue(value); } } xssfsheet.ForceFormulaRecalculation = true; //將內存數據寫到文件 using (FileStream fs = File.OpenWrite(reportFileName)) { xssfworkbook.Write(fs); xssfworkbook.Close(); } Thread.Sleep(100); } } catch (Exception ex) { _logger.Error($"導出數據出錯,message:{ex.Message},stackTrace:{ex.StackTrace}"); } finally { if (file != null) file.Close(); } sw.Stop(); _logger.Info($"日期:{currentTime},耗時{sw.Elapsed.TotalSeconds}秒"); } #region 獲取開始時間和結束時間 /// <summary> /// 獲取開始時間和結束時間 /// </summary> /// <param name="currentTime"></param> /// <param name="strBeginTime"></param> /// <param name="strEndTime"></param> private void GetTime(DateTime currentTime, out string strBeginTime, out string strEndTime) { DateTime beginTime; DateTime endTime; if (currentTime < currentTime.Date.AddHours(7.5)) { beginTime = currentTime.Date.AddDays(-1).AddHours(7.5);//前天7:30 endTime = currentTime.Date.AddHours(7.5);//當天的7:30 } else { beginTime = currentTime.Date.AddHours(7.5); endTime = currentTime.Date.AddDays(1).AddHours(7.5); } strBeginTime = beginTime.ToString("yyyy-MM-dd HH:mm"); strEndTime = endTime.ToString("yyyy-MM-dd HH:mm"); } #endregion #region 查詢數據 /// <summary> /// 查詢數據 /// </summary> /// <param name="strBeginTime"></param> /// <param name="strEndTime"></param> /// <param name="startRow"></param> /// <param name="endRow"></param> /// <returns></returns> private DataTable GetDataTable(string strBeginTime, string strEndTime, int startRow, int endRow) { var sql = $@" select * from ( select row_number() over(order by A asc,AB asc,AC asc) as rownumber, * from {ConfigHelper.ExcelExportTableName} where E between '{strBeginTime}' and '{strEndTime}' ) as t where rownumber between {startRow} and {endRow} "; DataTable dt = DapperSqlHelper.QueryDataTable(sql); return dt; } #endregion #region 查詢總數 /// <summary> /// 查詢總數 /// </summary> /// <param name="strBeginTime"></param> /// <param name="strEndTime"></param> /// <returns></returns> private int GetDataTableCount(string strBeginTime, string strEndTime) { var sql = $"select count(1) from {ConfigHelper.ExcelExportTableName} where E between '{strBeginTime}' and '{strEndTime}'"; DataTable dt = DapperSqlHelper.QueryDataTable(sql); var count = Convert.ToInt32(dt.Rows[0][0]); return count; } #endregion } }
一開始是一次性讀取符合條件的數據,因為數據量大,大概七八千條,而且每條記錄400個字段。所以后面優化成了分頁讀取,每次取100條數據,然后再往excel插入數據。