在報表導出、數據下載、批量匯出等場景中,將 DataSet 直接輸出為 Excel 文件是高頻需求。本文提供一個零依賴、基於 HTTP 響應流的通用導出方法,利用 Tab 分隔值(TSV)格式,無需安裝 Office 組件、無需第三方庫,即開即用。
public static void ExportToExcel(DataSet ds, string fileName = null)
{
if (ds == null || ds.Tables.Count == 0) return;
DataTable dt = ds.Tables[0];
if (dt.Rows.Count == 0) return;
// 1. 生成文件名
string name = fileName ?? $"Export_{DateTime.Now:yyyyMMddHHmmss}.xls";
// 2. 設置響應頭
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.Buffer = true;
response.Charset = "GB2312";
response.ContentEncoding = Encoding.GetEncoding("GB2312");
response.ContentType = "application/vnd.ms-excel";
response.AppendHeader("Content-Disposition", $"attachment;filename={HttpUtility.UrlEncode(name, Encoding.UTF8)}");
// 3. 導出列標題
var sb = new StringBuilder();
for (int i = 0; i < dt.Columns.Count; i++)
{
sb.Append(dt.Columns[i].Caption);
if (i < dt.Columns.Count - 1) sb.Append("\t");
else sb.Append("\n");
}
response.Write(sb.ToString());
sb.Clear();
// 4. 導出數據行
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
string val = row[i]?.ToString() ?? "";
// 處理包含 Tab/換行/雙引號的值
if (val.Contains("\t") || val.Contains("\n") || val.Contains("\""))
val = "\"" + val.Replace("\"", "\"\"") + "\"";
sb.Append(val);
if (i < dt.Columns.Count - 1) sb.Append("\t");
else sb.Append("\n");
}
response.Write(sb.ToString());
sb.Clear();
}
response.Flush();
response.End();
}
| 技術點 | 說明 |
|---|---|
| TSV 格式 | Excel 原生支援 Tab 分隔文本,打開無亂碼、無格式警告 |
| GB2312 編碼 | 中文 Excel 兼容性最佳,避免 UTF-8 BOM 導致亂碼 |
| StringBuilder | 減少字符串拼接內存分配,大數據量下性能顯著提升 |
| 特殊字符轉義 | 包含 Tab、換行、雙引號的值用雙引號包裹,內部雙引號轉義 |
| UrlEncode 文件名 | 解決中文文件名在不同瀏覽器下亂碼問題 |
// 1. 從數據庫獲取數據
DataSet ds = GetReportData(); // 你的查詢邏輯
// 2. 一鍵導出
ExportToExcel(ds, "月度銷售報表.xls");
public static void ExportToExcelMultiSheet(DataSet ds, string fileName)
{
// 注意:TSV 格式不支援多 Sheet,需使用真實 Excel 庫
// 推薦方案:引入 NPOI / EPPlus / ClosedXML
using (var workbook = new NPOI.HSSF.UserModel.HSSFWorkbook())
{
foreach (DataTable dt in ds.Tables)
{
var sheet = workbook.CreateSheet(dt.TableName);
// 寫入標題行
var headerRow = sheet.CreateRow(0);
for (int i = 0; i < dt.Columns.Count; i++)
headerRow.CreateCell(i).SetCellValue(dt.Columns[i].Caption);
// 寫入數據行
for (int r = 0; r < dt.Rows.Count; r++)
{
var row = sheet.CreateRow(r + 1);
for (int c = 0; c < dt.Columns.Count; c++)
row.CreateCell(c).SetCellValue(dt.Rows[r][c]?.ToString() ?? "");
}
}
// 輸出到響應流
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentType = "application/vnd.ms-excel";
response.AppendHeader("Content-Disposition", $"attachment;filename={fileName}");
using (var ms = new MemoryStream())
{
workbook.Write(ms);
response.BinaryWrite(ms.ToArray());
}
response.End();
}
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| TSV 響應流(本文) | 零依賴、極簡代碼、無內存壓力、流式輸出 | 無樣式/公式/多 Sheet、大數據可能觸發 Excel 警告 | 簡單報表、臨時導出、無 Office 環境服務器 |
| NPOI / EPPlus | 完整 Excel 功能、樣式、公式、多 Sheet、.xlsx 支援 | 需引用 DLL、大數據需內存構建 Workbook | 正式報表、複雜格式、生產系統標準化導出 |
| Open XML SDK | 微軟官方、無 Office 依賴、流式寫入支援 | API 底層、代碼量大、學習曲線陡峭 | 高性能、大文件、長期維護項目 |
ThreadAbortException,屬正常行為,catch 時需 Thread.ResetAbort() 或使用 HttpContext.Current.ApplicationInstance.CompleteRequest()Server.ScriptTimeout 或 httpRuntime executionTimeout\t 或單引號 ' 強制文本格式本文提供的 TSV 流式導出方案以「零依賴、高性能、代碼極簡」三大優勢,完美覆蓋 80% 的簡單導出場景。對於需要專業報表格式的項目,建議引入 NPOI/EPPlus 構建統一導出服務。選對工具,事半功倍。