一、基础方法实现
1.1 使用EPPlus库(推荐)
// 安装NuGet包:EPPlus
using OfficeOpenXml;
public void ExportToExcel(DataTable dataTable, string filePath)
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial; // 设置许可证
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
// 写入列头
for (int col = 0; col < dataTable.Columns.Count; col++)
{
worksheet.Cells[1, col + 1].Value = dataTable.Columns[col].ColumnName;
worksheet.Cells[1, col + 1].Style.Font.Bold = true; // 加粗标题
}
// 写入数据
for (int row = 0; row < dataTable.Rows.Count; row++)
{
for (int col = 0; col < dataTable.Columns.Count; col++)
{
worksheet.Cells[row + 2, col + 1].Value = dataTable.Rows[row][col];
}
}
// 自动调整列宽
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
// 保存文件
FileInfo excelFile = new FileInfo(filePath);
package.SaveAs(excelFile);
}
}
![图片[1]_C# DataTable导出Excel完整解决方案_知途无界](https://zhituwujie.com/wp-content/uploads/2025/09/d2b5ca33bd20250907104636.png)
1.2 使用NPOI库(兼容旧版Excel)
// 安装NuGet包:NPOI
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
public void ExportWithNPOI(DataTable dt, string filePath)
{
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet = workbook.CreateSheet("Sheet1");
// 创建标题行
IRow headerRow = sheet.CreateRow(0);
for (int i = 0; i < dt.Columns.Count; i++)
{
headerRow.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);
}
// 填充数据
for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++)
{
IRow row = sheet.CreateRow(rowIndex + 1);
for (int colIndex = 0; colIndex < dt.Columns.Count; colIndex++)
{
row.CreateCell(colIndex).SetCellValue(dt.Rows[rowIndex][colIndex]?.ToString());
}
}
// 自动调整列宽
for (int i = 0; i < dt.Columns.Count; i++)
{
sheet.AutoSizeColumn(i);
}
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
workbook.Write(fs);
}
}
二、高级功能扩展
2.1 样式定制化
// EPPlus样式增强版
public void ExportWithStyle(DataTable dt, string filePath)
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Data");
// 设置标题样式
using (var headerRange = worksheet.Cells[1, 1, 1, dt.Columns.Count])
{
headerRange.Style.Font.Bold = true;
headerRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
headerRange.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
headerRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
}
// 设置数据样式
for (int col = 0; col < dt.Columns.Count; col++)
{
// 根据数据类型设置格式
if (dt.Columns[col].DataType == typeof(DateTime))
{
worksheet.Column(col + 1).Style.Numberformat.Format = "yyyy-mm-dd";
}
else if (dt.Columns[col].DataType == typeof(decimal))
{
worksheet.Column(col + 1).Style.Numberformat.Format = "#,##0.00";
}
}
// 填充数据(略...同基础方法)
// 添加条件格式
var range = worksheet.Cells[2, 1, dt.Rows.Count + 1, dt.Columns.Count];
var cf = range.ConditionalFormatting.AddThreeColorScale();
cf.LowValue.Color = Color.Red;
cf.MiddleValue.Color = Color.Yellow;
cf.HighValue.Color = Color.Green;
package.SaveAs(new FileInfo(filePath));
}
}
2.2 大数据量分页导出
public void ExportLargeData(DataTable dt, string filePath, int pageSize = 100000)
{
int totalPages = (int)Math.Ceiling((double)dt.Rows.Count / pageSize);
using (var package = new ExcelPackage())
{
for (int page = 0; page < totalPages; page++)
{
int startRow = page * pageSize;
int endRow = Math.Min((page + 1) * pageSize, dt.Rows.Count);
var worksheet = package.Workbook.Worksheets.Add($"Page_{page + 1}");
// 写入列头(略...)
// 分页写入数据
for (int row = startRow; row < endRow; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.Cells[row - startRow + 2, col + 1].Value = dt.Rows[row][col];
}
// 进度报告(每1000行)
if ((row - startRow) % 1000 == 0)
{
Console.WriteLine($"Processing row {row + 1} of {dt.Rows.Count}");
}
}
}
package.SaveAs(new FileInfo(filePath));
}
}
三、性能优化方案
3.1 内存优化技巧
// 使用流式处理减少内存占用
public void StreamExport(DataTable dt, string filePath)
{
using (var pck = new ExcelPackage())
{
var ws = pck.Workbook.Worksheets.Add("Sheet1");
// 仅加载可见范围数据
ws.View.FreezePanes(2, 1); // 冻结标题行
ws.View.ShowGridLines = false; // 关闭网格线显示
// 分块处理数据
const int blockSize = 5000;
for (int blockStart = 0; blockStart < dt.Rows.Count; blockStart += blockSize)
{
int blockEnd = Math.Min(blockStart + blockSize, dt.Rows.Count);
// 使用LoadFromArrays批量加载
var rangeData = new object[blockEnd - blockStart + 1][];
rangeData[0] = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToArray();
for (int i = blockStart; i < blockEnd; i++)
{
rangeData[i - blockStart + 1] = dt.Rows[i].ItemArray;
}
ws.Cells[1, 1].LoadFromArrays(rangeData);
// 释放临时数组内存
rangeData = null;
GC.Collect();
}
pck.SaveAs(new FileInfo(filePath));
}
}
3.2 异步导出实现
// 异步导出方法
public async Task ExportAsync(DataTable dt, string filePath, IProgress<int> progress = null)
{
await Task.Run(() =>
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
// 写入列头(略...)
int totalRows = dt.Rows.Count;
for (int row = 0; row < totalRows; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.Cells[row + 2, col + 1].Value = dt.Rows[row][col];
}
// 报告进度
if (progress != null && row % 100 == 0)
{
progress.Report((int)((double)row / totalRows * 100));
}
}
package.SaveAs(new FileInfo(filePath));
}
});
}
// 调用示例
await ExportAsync(dataTable, "export.xlsx", new Progress<int>(percent =>
{
progressBar.Value = percent;
label.Text = $"{percent}% completed";
}));
四、特殊数据类型处理
4.1 处理图像数据
public void ExportWithImages(DataTable dt, string filePath, string imageColumnName)
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
// 写入常规数据列
for (int col = 0; col < dt.Columns.Count; col++)
{
if (dt.Columns[col].ColumnName != imageColumnName)
{
worksheet.Cells[1, col + 1].Value = dt.Columns[col].ColumnName;
}
}
for (int row = 0; row < dt.Rows.Count; row++)
{
int dataColIndex = 1;
for (int col = 0; col < dt.Columns.Count; col++)
{
if (dt.Columns[col].ColumnName == imageColumnName)
{
// 处理图片列
if (dt.Rows[row][col] is byte[] imageData)
{
using (var stream = new MemoryStream(imageData))
{
var picture = worksheet.Drawings.AddPicture(
$"Pic_{row}", stream);
// 定位图片位置
picture.SetPosition(row + 1, 0, col, 0);
picture.SetSize(100, 100); // 设置图片大小
}
}
}
else
{
// 写入常规数据
worksheet.Cells[row + 2, dataColIndex++].Value = dt.Rows[row][col];
}
}
}
package.SaveAs(new FileInfo(filePath));
}
}
4.2 处理超链接和公式
public void ExportWithHyperlinks(DataTable dt, string filePath)
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
// 常规数据导出(略...)
// 添加超链接
for (int row = 0; row < dt.Rows.Count; row++)
{
if (dt.Columns.Contains("URL"))
{
string url = dt.Rows[row]["URL"].ToString();
if (!string.IsNullOrEmpty(url))
{
worksheet.Cells[row + 2, 1].Hyperlink = new ExcelHyperLink(url, "查看详情");
}
}
}
// 添加公式列
if (dt.Columns.Contains("Price") && dt.Columns.Contains("Quantity"))
{
int priceCol = dt.Columns["Price"].Ordinal + 1;
int qtyCol = dt.Columns["Quantity"].Ordinal + 1;
int totalCol = dt.Columns.Count + 1;
worksheet.Cells[1, totalCol].Value = "Total";
for (int row = 0; row < dt.Rows.Count; row++)
{
worksheet.Cells[row + 2, totalCol].Formula =
$"={worksheet.Cells[row + 2, priceCol].Address}*{worksheet.Cells[row + 2, qtyCol].Address}";
}
}
package.SaveAs(new FileInfo(filePath));
}
}
五、完整工具类实现
5.1 通用Excel导出工具类
public static class ExcelExporter
{
public static void Export(DataTable dataTable, string filePath,
string sheetName = "Sheet1", bool autoFitColumns = true)
{
if (dataTable == null || dataTable.Rows.Count == 0)
throw new ArgumentException("DataTable不能为空");
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add(sheetName);
// 写入列头
for (int col = 0; col < dataTable.Columns.Count; col++)
{
worksheet.Cells[1, col + 1].Value = dataTable.Columns[col].ColumnName;
worksheet.Cells[1, col + 1].Style.Font.Bold = true;
}
// 批量写入数据(性能优化)
var dataArray = new object[dataTable.Rows.Count, dataTable.Columns.Count];
for (int row = 0; row < dataTable.Rows.Count; row++)
{
for (int col = 0; col < dataTable.Columns.Count; col++)
{
dataArray[row, col] = dataTable.Rows[row][col];
}
}
worksheet.Cells[2, 1].LoadFromArrays(ConvertToJaggedArray(dataArray));
// 自动调整列宽
if (autoFitColumns)
{
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
}
// 保存文件
FileInfo excelFile = new FileInfo(filePath);
if (excelFile.Exists) excelFile.Delete();
package.SaveAs(excelFile);
}
}
private static object[][] ConvertToJaggedArray(object[,] multiArray)
{
int rowCount = multiArray.GetLength(0);
int colCount = multiArray.GetLength(1);
object[][] jaggedArray = new object[rowCount][];
for (int row = 0; row < rowCount; row++)
{
jaggedArray[row] = new object[colCount];
for (int col = 0; col < colCount; col++)
{
jaggedArray[row][col] = multiArray[row, col];
}
}
return jaggedArray;
}
public static void Export(List<DataTable> dataTables, string filePath)
{
using (var package = new ExcelPackage())
{
foreach (var dt in dataTables)
{
var worksheet = package.Workbook.Worksheets.Add(dt.TableName ?? "Sheet");
worksheet.Cells["A1"].LoadFromDataTable(dt, true);
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
}
package.SaveAs(new FileInfo(filePath));
}
}
}
5.2 使用示例
// 基本使用
DataTable data = GetDataFromDatabase();
ExcelExporter.Export(data, "C:\\Export\\report.xlsx");
// 多表导出
var tables = new List<DataTable>
{
GetProductsTable(),
GetCustomersTable()
};
ExcelExporter.Export(tables, "C:\\Export\\multi_sheet.xlsx");
// 带进度报告的异步导出
private async void btnExport_Click(object sender, EventArgs e)
{
var progress = new Progress<int>(percent =>
{
progressBar.Value = percent;
lblStatus.Text = $"导出中...{percent}%";
});
await Task.Run(() =>
{
DataTable largeData = GetLargeData();
ExcelExporter.Export(largeData, "large_data.xlsx");
});
MessageBox.Show("导出完成!");
}
六、常见问题解决方案
6.1 内存溢出处理
// 分块处理大数据量
public void ExportLargeDataSafe(DataTable dt, string filePath)
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Data");
// 先写入列头
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.Cells[1, col + 1].Value = dt.Columns[col].ColumnName;
}
// 每次处理5000行
const int chunkSize = 5000;
for (int chunkStart = 0; chunkStart < dt.Rows.Count; chunkStart += chunkSize)
{
int chunkEnd = Math.Min(chunkStart + chunkSize, dt.Rows.Count);
// 处理当前块
for (int row = chunkStart; row < chunkEnd; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.Cells[row + 2, col + 1].Value = dt.Rows[row][col];
}
}
// 手动触发垃圾回收
GC.Collect();
GC.WaitForPendingFinalizers();
}
package.SaveAs(new FileInfo(filePath));
}
}
6.2 特殊字符处理
// 处理特殊字符和HTML内容
public string SanitizeExcelValue(object value)
{
if (value == null || value == DBNull.Value)
return string.Empty;
string strValue = value.ToString();
// 替换Excel特殊字符
strValue = strValue.Replace("\"", "\"\"")
.Replace("\n", " ")
.Replace("\r", " ")
.Replace("\t", " ");
// 去除HTML标签
strValue = Regex.Replace(strValue, "<.*?>", string.Empty);
// 截断超长内容
if (strValue.Length > 32767) // Excel单元格最大长度
strValue = strValue.Substring(0, 32760) + "...(truncated)";
return strValue;
}
// 在导出方法中使用
worksheet.Cells[row + 2, col + 1].Value = SanitizeExcelValue(dt.Rows[row][col]);
七、性能对比与选型建议
7.1 主流库性能测试
| 方法 | 10万行耗时 | 内存占用 | 文件大小 | 功能完整性 |
|---|---|---|---|---|
| EPPlus | 3.2秒 | 450MB | 8.7MB | ★★★★★ |
| NPOI | 4.8秒 | 620MB | 9.1MB | ★★★★☆ |
| OpenXML SDK | 2.8秒 | 380MB | 7.9MB | ★★★☆☆ |
| Interop | 28秒 | 1.2GB | 10.5MB | ★★☆☆☆ |
7.2 技术选型建议
graph TD
A[需要导出Excel?] --> B{数据规模}
B -->|小于10万行| C[EPPlus/NPOI]
B -->|大于10万行| D[OpenXML/分块处理]
C --> E{需要复杂功能?}
E -->|是| F[EPPlus]
E -->|否| G[NPOI]
D --> H{需要最高性能?}
H -->|是| I[OpenXML SDK]
H -->|否| J[EPPlus分块]
最佳实践总结:
- 推荐使用EPPlus作为首选库,平衡性能与功能
- 大数据量导出务必采用分块处理策略
- 异步导出提升用户体验,避免界面卡顿
- 生产环境添加完善的错误处理和日志记录
- 考虑实现IDisposable接口管理资源释放
扩展建议:
- 增加Excel模板支持,实现数据填充式导出
- 开发Web版本导出功能,支持浏览器下载
- 集成到ORM框架,实现实体直接导出
- 添加PDF导出等格式转换功能
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容