### C# 导出 Excel 的方法与技巧
在软件开发领域,特别是在企业级应用中,经常需要处理大量的数据导出工作,例如将数据库中的数据导出到 Excel 文件中供用户查看或进一步分析。C# 作为一种广泛使用的面向对象编程语言,在处理这类任务时表现出了强大的功能和灵活性。
#### 一、C# 导出 Excel 的基本原理
在 C# 中,导出 Excel 的一种常见方式是通过使用 `Microsoft.Office.Interop.Excel` 命名空间提供的 COM 组件来实现。这种方式可以让我们直接操作 Excel 对象模型,从而完成各种复杂的操作,如创建工作簿、添加工作表、设置单元格样式等。
#### 二、关键代码解析
在提供的代码片段中,可以看到一个名为 `DataTableToExcel` 的方法,该方法接收两个参数:一个 `DataTable` 对象(包含待导出的数据)和一个字符串类型的文件名。下面对这段代码进行详细的解析:
```csharp
using Excel = Microsoft.Office.Interop.Excel;
public class ExcelHelper
{
private Excel.Application _xlApp = null;
/// <summary>
/// 将 DataTable 导出到 Excel
/// </summary>
/// <param name="tmpDataTable">需要导出的 DataTable</param>
/// <param name="strFileName">Excel 文件路径</param>
public void DataTableToExcel(System.Data.DataTable tmpDataTable, string strFileName)
{
if (tmpDataTable == null)
{
return;
}
long rowNum = tmpDataTable.Rows.Count;
int columnNum = tmpDataTable.Columns.Count;
_xlApp = new Excel.Application();
_xlApp.DisplayAlerts = false; // 关闭警告提示
_xlApp.Visible = false;
Excel.Workbooks workbooks = _xlApp.Workbooks;
Excel.Workbook workbook = workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets[1]; // 获取 sheet1
try
{
if (rowNum > 65536) // Excel 单个工作表的最大行数为 65536
{
long pageRows = 65535; // 每页显示的行数,略小于 65536
int pageCount = (int)(rowNum / pageRows); // 计算分页数量
if (pageCount * pageRows < rowNum) // 当总行数除以每页行数有余数时,页数加一
{
pageCount++;
}
for (int sc = 1; sc <= pageCount; sc++)
{
if (sc > 1)
{
object missing = System.Reflection.Missing.Value;
worksheet = (Excel.Worksheet)workbook.Worksheets.Add(missing, missing, missing, missing); // 添加新的 sheet
}
else
{
worksheet = (Excel.Worksheet)workbook.Worksheets[sc]; // 获取 sheet1
}
string[,] datas = new string[pageRows + 1, columnNum];
for (int i = 0; i < columnNum; i++) // 写入列头
{
datas[0, i] = tmpDataTable.Columns[i].Caption; // 列头信息
}
Excel.Range range = worksheet.get_Range(worksheet.Cells[1, 1], worksheet.Cells[1, columnNum]);
range.Interior.ColorIndex = 15; // 设置背景色为白色
range.Font.Bold = true;
range.Font.Size = 9;
int init = (int)((sc - 1) * pageRows);
int index = 0;
int result = (sc == pageCount && pageRows * sc >= rowNum) ? (int)rowNum : (int)(pageRows * sc);
for (int r = init; r < result; r++)
{
index++;
for (int i = 0; i < columnNum; i++)
{
object obj = tmpDataTable.Rows[r][tmpDataTable.Columns[i].ToString()];
datas[index, i] = obj == null ? "" : "'" + obj.ToString().Trim(); // 处理空值和文本值
}
System.Windows.Forms.Application.DoEvents(); // 释放 UI 更新
}
Excel.Range fchR = worksheet.get_Range(worksheet.Cells[1, 1], worksheet.Cells[index + 1, columnNum]);
fchR.Value2 = datas;
}
}
else
{
// 如果数据量较小,则直接写入单个工作表
// 逻辑与上述分页写入类似
}
}
finally
{
// 保存并关闭 Excel 文件
workbook.SaveAs(strFileName);
workbook.Close(false, null, null);
_xlApp.Quit();
// 释放资源
System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(_xlApp);
}
}
}
```
#### 三、关键点解析
1. **初始化 Excel 应用程序**:使用 `new Excel.Application()` 创建 Excel 应用程序实例。
2. **禁用警告和可见性**:设置 `_xlApp.DisplayAlerts = false;` 和 `_xlApp.Visible = false;` 来避免弹出警告对话框和防止 Excel 窗口显示。
3. **创建工作簿和工作表**:通过 `_xlApp.Workbooks.Add` 方法创建一个新的工作簿,并获取第一个工作表。
4. **处理大数据**:当数据行数超过 Excel 工作表的最大限制(65536 行)时,代码会自动进行分页处理,即将数据分割到多个工作表中。
5. **写入数据**:使用双重循环遍历 `DataTable` 中的数据,并将其写入 Excel 的单元格中。同时,对数据进行了简单的处理,例如处理空值和确保文本值正确写入。
6. **格式化**:设置了单元格的字体大小、加粗以及背景颜色等属性。
7. **释放资源**:在 `finally` 块中关闭工作簿、退出 Excel 应用程序并释放相关资源。
#### 四、注意事项
- 在实际应用中,需要注意使用 COM 组件可能会导致的一些问题,如内存泄漏、异常处理等。
- 对于非常大的数据集,考虑使用其他技术,如 OpenXML 或 EPPlus 等第三方库,这些库通常提供更好的性能和更低的内存消耗。
- 为了提高效率,可以采用异步方式处理数据和 UI 更新。
- 对于安全性敏感的应用场景,建议使用非交互式的方式处理 Excel 文件,避免用户界面操作可能带来的安全风险。
通过上述分析,我们可以看到 C# 提供了丰富的工具和技术来实现高效的数据导出到 Excel 的功能,这对于开发人员来说是非常有用的。