DataTable更新Excel模板代码执行过慢,求优化方案
高效更新Excel模板中DATA工作表的C#实现方案
我们公司有一款用于数据筛选的Excel模板,只需更新其中名为"DATA"的工作表即可。我编写了如下C#代码实现该功能,但执行速度极慢,希望得到更高效的实现方式:
private void EsportaInTemplateExcelVL(string NomeFile) { string fileNameTemp = NomeFile;//System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx"; string FileXls = Application.StartupPath + @"\Support\PrintFormat\VL_LAB_updated.xls"; if (!File.Exists(FileXls)) { MessageBox("File template VL_LAB_updated.xls not found"); return; } System.IO.File.Copy(FileXls, fileNameTemp); Excel.Application excelApp = new Excel.Application(); Excel.Workbook wb = excelApp.Application.Workbooks.Open(fileNameTemp, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); Excel.Sheets excelSheets = excelApp.Worksheets;// var ws = excelApp.Worksheets; Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelSheets.get_Item("DATA"); string[] col = { "A", "B", "C", "D", "E", "F", "G", "H", "I","J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X","Y", "Z" }; //Head Columns for (int C = 0; C < dt.Columns.Count ; C++) { string Cella = col[C].ToString() + (0 + 1).ToString();//i parte da zero Excel.Range excelCell = (Excel.Range)excelWorksheet.get_Range(Cella, Cella); excelCell.Value = dt.Columns[C].ColumnName; } //all data for (int i = 0; i < dt.Rows.Count ; i++) { for (int C = 0; C < dt.Columns.Count ; C++) { string Cella = col[C].ToString() + (i + 2).ToString(); Excel.Range excelCell = (Excel.Range)excelWorksheet.get_Range(Cella, Cella); excelCell.Value = "'" + dt.Rows[i][C].ToString(); } } wb.Close(true); excelApp.Quit(); MessageBox("Done"); }
原代码性能瓶颈分析
- 逐单元格COM交互:每次循环都创建
Excel.Range对象并赋值,频繁的跨进程COM调用会产生巨大开销,这是速度慢的核心原因。 - 冗余字符串操作:循环中反复拼接单元格地址(如"A1"),增加不必要的计算成本。
- 未禁用Excel界面更新:默认状态下Excel会实时刷新界面,大量单元格更新会触发多次重绘,拖慢执行速度。
高效优化实现方案
以下是优化后的代码,核心思路是减少COM交互次数和批量写入数据:
private void EsportaInTemplateExcelVL(string NomeFile) { string fileNameTemp = NomeFile; string FileXls = Application.StartupPath + @"\Support\PrintFormat\VL_LAB_updated.xls"; if (!File.Exists(FileXls)) { MessageBox.Show("未找到模板文件VL_LAB_updated.xls"); return; } // 覆盖式复制模板文件 System.IO.File.Copy(FileXls, fileNameTemp, overwrite: true); Excel.Application excelApp = new Excel.Application(); try { // 关闭Excel界面相关功能,大幅提升速度 excelApp.Visible = false; excelApp.DisplayAlerts = false; excelApp.ScreenUpdating = false; Excel.Workbook wb = excelApp.Workbooks.Open(fileNameTemp); Excel.Worksheet excelWorksheet = (Excel.Worksheet)wb.Worksheets["DATA"]; int totalRows = dt.Rows.Count; int totalCols = dt.Columns.Count; // 准备二维数组存储所有数据(含表头) object[,] dataBatch = new object[totalRows + 1, totalCols]; // 填充表头 for (int col = 0; col < totalCols; col++) { dataBatch[0, col] = dt.Columns[col].ColumnName; } // 填充数据行 for (int row = 0; row < totalRows; row++) { for (int col = 0; col < totalCols; col++) { // 保留原代码的单引号前缀,确保文本格式 dataBatch[row + 1, col] = "'" + dt.Rows[row][col].ToString(); } } // 批量写入数据,仅需一次COM交互 Excel.Range targetRange = excelWorksheet.Range[ excelWorksheet.Cells[1, 1], excelWorksheet.Cells[totalRows + 1, totalCols] ]; targetRange.Value = dataBatch; // 保存并关闭工作簿 wb.Close(true); MessageBox.Show("操作完成"); } finally { // 恢复Excel默认设置 excelApp.ScreenUpdating = true; excelApp.DisplayAlerts = true; excelApp.Quit(); // 释放COM对象,避免内存泄漏 System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); } }
优化点说明
- 批量数据写入:将所有数据先存入二维数组,再一次性写入Excel的连续区域,把原本上万次的COM调用缩减为1次。
- 禁用界面刷新:关闭
ScreenUpdating、Visible等属性,避免Excel实时绘制界面,减少资源消耗。 - 直接使用行列索引:通过
Cells[row, col]定位范围,无需拼接单元格地址字符串,减少计算开销。 - 安全释放资源:使用
finally块确保Excel资源被正确释放,避免内存泄漏问题。
额外性能建议
如果处理的数据量极大(超过10万行),可以考虑使用EPPlus或NPOI等开源库,这些库无需依赖本地Excel客户端,性能更优且部署更便捷。
内容的提问来源于stack exchange,提问作者Amodio De Cicco
相关产品推荐
相关产品推荐

