EPPlusToExcel.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. 
  2. using OfficeOpenXml;
  3. using OfficeOpenXml.Style;
  4. using System;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Windows.Forms;
  10. namespace PTMedicalInsurance.Common
  11. {
  12. /// <summary>
  13. /// EPPlus DataTable导出Excel工具类
  14. /// 使用前需安装: Install-Package EPPlus
  15. /// </summary>
  16. public static class EPPlusExcelExporter
  17. {
  18. // 静态构造函数设置EPPlus许可证(EPPlus 5+需要)
  19. static EPPlusExcelExporter()
  20. {
  21. // EPPlus 5+ 需要设置许可证类型
  22. // 非商业用途使用:
  23. ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
  24. // 商业用途请购买许可证后使用:
  25. // ExcelPackage.LicenseContext = LicenseContext.Commercial;
  26. }
  27. /// <summary>
  28. /// DataTable导出Excel(基础版本)
  29. /// </summary>
  30. /// <param name="dataTable">数据源</param>
  31. /// <param name="filePath">导出路径</param>
  32. /// <param name="sheetName">Sheet名称</param>
  33. public static void ExportToExcel(DataTable dataTable, string filePath, string sheetName = "Sheet1")
  34. {
  35. if (dataTable == null || dataTable.Rows.Count == 0)
  36. throw new ArgumentException("DataTable为空或没有数据");
  37. // 确保目录存在
  38. string directory = Path.GetDirectoryName(filePath);
  39. if (!Directory.Exists(directory))
  40. Directory.CreateDirectory(directory);
  41. using (var package = new ExcelPackage())
  42. {
  43. var worksheet = package.Workbook.Worksheets.Add(sheetName);
  44. // 写入数据(包含表头)
  45. worksheet.Cells[1, 1].LoadFromDataTable(dataTable, true);
  46. // 设置表头样式
  47. FormatHeader(worksheet, dataTable.Columns.Count);
  48. // 自动调整列宽
  49. worksheet.Cells.AutoFitColumns();
  50. // 保存文件
  51. package.SaveAs(new FileInfo(filePath));
  52. }
  53. }
  54. /// <summary>
  55. /// DataTable导出Excel(分批处理版本 - 每500行处理一次)
  56. /// </summary>
  57. /// <param name="dataTable">数据源</param>
  58. /// <param name="filePath">导出路径</param>
  59. /// <param name="batchSize">每批处理行数(默认500)</param>
  60. /// <param name="sheetName">Sheet名称</param>
  61. public static void ExportToExcelBatch(DataTable dataTable, string filePath, int batchSize = 500)
  62. {
  63. string sheetName = "Sheet1";
  64. if (dataTable == null || dataTable.Rows.Count == 0)
  65. throw new ArgumentException("DataTable为空或没有数据");
  66. // 确保目录存在
  67. string directory = Path.GetDirectoryName(filePath);
  68. if (!Directory.Exists(directory))
  69. Directory.CreateDirectory(directory);
  70. int totalRows = dataTable.Rows.Count;
  71. int columnCount = dataTable.Columns.Count;
  72. using (var package = new ExcelPackage())
  73. {
  74. var worksheet = package.Workbook.Worksheets.Add(sheetName);
  75. // 写入表头
  76. for (int col = 0; col < columnCount; col++)
  77. {
  78. worksheet.Cells[1, col + 1].Value = dataTable.Columns[col].ColumnName;
  79. }
  80. FormatHeader(worksheet, columnCount);
  81. // 分批写入数据
  82. int currentRow = 2; // 从第2行开始(第1行是表头)
  83. int batchCount = (int)Math.Ceiling((double)totalRows / batchSize);
  84. Console.WriteLine($"总数据: {totalRows} 行, 分批: {batchCount} 批, 每批: {batchSize} 行");
  85. for (int batch = 0; batch < batchCount; batch++)
  86. {
  87. int startRow = batch * batchSize;
  88. int endRow = Math.Min(startRow + batchSize, totalRows);
  89. int rowsInBatch = endRow - startRow;
  90. Console.WriteLine($"处理第 {batch + 1}/{batchCount} 批: 行 {startRow + 1} - {endRow}");
  91. // 当前批次的数据数组
  92. object[,] batchData = new object[rowsInBatch, columnCount];
  93. for (int i = 0; i < rowsInBatch; i++)
  94. {
  95. for (int j = 0; j < columnCount; j++)
  96. {
  97. batchData[i, j] = dataTable.Rows[startRow + i][j];
  98. }
  99. }
  100. // 写入当前批次到Excel
  101. var range = worksheet.Cells[currentRow, 1, currentRow + rowsInBatch - 1, columnCount];
  102. range.Value = batchData;
  103. currentRow += rowsInBatch;
  104. }
  105. // 格式化数据区域
  106. FormatDataRange(worksheet, totalRows, columnCount);
  107. // 自动调整列宽
  108. worksheet.Cells.AutoFitColumns();
  109. // 冻结首行
  110. worksheet.View.FreezePanes(2, 1);
  111. // 保存文件
  112. package.SaveAs(new FileInfo(filePath));
  113. Console.WriteLine($"导出完成: {filePath}");
  114. MessageBox.Show(" 导出完毕:"+filePath);
  115. }
  116. }
  117. /// <summary>
  118. /// 大数据导出(自动分Sheet,每个Sheet最多100万行)
  119. /// </summary>
  120. public static void ExportLargeData(DataTable dataTable, string filePath, int rowsPerSheet = 1000000)
  121. {
  122. if (dataTable == null || dataTable.Rows.Count == 0)
  123. throw new ArgumentException("DataTable为空或没有数据");
  124. string directory = Path.GetDirectoryName(filePath);
  125. if (!Directory.Exists(directory))
  126. Directory.CreateDirectory(directory);
  127. int totalRows = dataTable.Rows.Count;
  128. int columnCount = dataTable.Columns.Count;
  129. int sheetCount = (int)Math.Ceiling((double)totalRows / rowsPerSheet);
  130. using (var package = new ExcelPackage())
  131. {
  132. for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++)
  133. {
  134. string sheetName = sheetCount == 1 ? "数据" : $"数据_{sheetIndex + 1}";
  135. var worksheet = package.Workbook.Worksheets.Add(sheetName);
  136. // 当前Sheet的数据范围
  137. int startRow = sheetIndex * rowsPerSheet;
  138. int endRow = Math.Min(startRow + rowsPerSheet, totalRows);
  139. int rowsInSheet = endRow - startRow;
  140. // 写入表头
  141. for (int col = 0; col < columnCount; col++)
  142. {
  143. worksheet.Cells[1, col + 1].Value = dataTable.Columns[col].ColumnName;
  144. }
  145. FormatHeader(worksheet, columnCount);
  146. // 分批写入数据(每批500行)
  147. int batchSize = 500;
  148. int currentRow = 2;
  149. int batchesInSheet = (int)Math.Ceiling((double)rowsInSheet / batchSize);
  150. for (int batch = 0; batch < batchesInSheet; batch++)
  151. {
  152. int batchStart = startRow + batch * batchSize;
  153. int batchEnd = Math.Min(batchStart + batchSize, endRow);
  154. int rowsInBatch = batchEnd - batchStart;
  155. object[,] batchData = new object[rowsInBatch, columnCount];
  156. for (int i = 0; i < rowsInBatch; i++)
  157. {
  158. for (int j = 0; j < columnCount; j++)
  159. {
  160. batchData[i, j] = dataTable.Rows[batchStart + i][j];
  161. }
  162. }
  163. var range = worksheet.Cells[currentRow, 1, currentRow + rowsInBatch - 1, columnCount];
  164. range.Value = batchData;
  165. currentRow += rowsInBatch;
  166. }
  167. FormatDataRange(worksheet, rowsInSheet, columnCount);
  168. worksheet.Cells.AutoFitColumns();
  169. worksheet.View.FreezePanes(2, 1);
  170. }
  171. package.SaveAs(new FileInfo(filePath));
  172. }
  173. }
  174. /// <summary>
  175. /// DataTable转内存流(适用于Web下载)
  176. /// </summary>
  177. public static MemoryStream ExportToStream(DataTable dataTable, string sheetName = "Sheet1")
  178. {
  179. if (dataTable == null || dataTable.Rows.Count == 0)
  180. throw new ArgumentException("DataTable为空或没有数据");
  181. using (var package = new ExcelPackage())
  182. {
  183. var worksheet = package.Workbook.Worksheets.Add(sheetName);
  184. worksheet.Cells[1, 1].LoadFromDataTable(dataTable, true);
  185. FormatHeader(worksheet, dataTable.Columns.Count);
  186. worksheet.Cells.AutoFitColumns();
  187. var stream = new MemoryStream();
  188. package.SaveAs(stream);
  189. stream.Position = 0;
  190. return stream;
  191. }
  192. }
  193. #region 私有方法
  194. /// <summary>
  195. /// 设置表头样式
  196. /// </summary>
  197. private static void FormatHeader(ExcelWorksheet worksheet, int columnCount)
  198. {
  199. var headerRange = worksheet.Cells[1, 1, 1, columnCount];
  200. headerRange.Style.Font.Bold = true;
  201. headerRange.Style.Font.Size = 11;
  202. headerRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
  203. headerRange.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(192, 192, 192)); // 灰色
  204. headerRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
  205. headerRange.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
  206. headerRange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
  207. }
  208. /// <summary>
  209. /// 设置数据区域样式
  210. /// </summary>
  211. private static void FormatDataRange(ExcelWorksheet worksheet, int dataRows, int columnCount)
  212. {
  213. var dataRange = worksheet.Cells[2, 1, dataRows + 1, columnCount];
  214. dataRange.Style.Font.Size = 10;
  215. dataRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
  216. dataRange.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
  217. // 添加边框
  218. dataRange.Style.Border.Top.Style = ExcelBorderStyle.Thin;
  219. dataRange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
  220. dataRange.Style.Border.Left.Style = ExcelBorderStyle.Thin;
  221. dataRange.Style.Border.Right.Style = ExcelBorderStyle.Thin;
  222. // 设置行高
  223. worksheet.DefaultRowHeight = 18;
  224. }
  225. #endregion
  226. }
  227. }