输出DataSet到Excel






4.65/5 (15投票s)
允许导出多个表,并适当地标记文本列。使用 Excel 的 XML 格式。
引言
我这样做是因为我想快速将整个 DataSet
(多个表)导出到 Excel。我没有为字段添加任何额外的自定义,但我想确保日期、布尔值、数字和文本都格式正确。
这段代码实现了这一点。
在某个时候,我想创建一个 GridView
类型的组件,以便我可以更详细地描述每个项目。例如,我最近的项目需要我创建一个使用给定条形码字体(“Free 3 of 9”)格式化的列,该字体要求我在项目编号前后加上 *。下面的解决方案并不容易做到这一点,所以... 并不完美。如果有人做过类似的事情,请告诉我 :)
有关将 Excel 导入到 XML 的信息,请参阅这篇文章。
注意:此方法不需要在服务器上安装 Excel。
背景
我希望数据集中的每个表都有命名。
ds.Tables[0].TableName = "Colors";
ds.Tables[1].TableName = "Shapes";
我修改了它,允许你传入一个 List<Table>
,以防你没有将它们放在 DataSet
中。无论哪种方式都没有什么大问题。
为什么我使用 XmlTextWriter
,而似乎只使用了 WriteRaw
?我希望它能够使用“x.WriteString(row[i].ToString());
”修复任何特殊字符。请注意,这仍然可能对某些字符存在问题,因为我没有对其进行太多测试。
Using the Code
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Xml;
public void Convert(DataSet ds, string fileName) {
Convert(ds.Tables, fileName);
}
public void Convert(IEnumerable tables, string fileName) {
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("content-disposition",
"attachment; filename=" + fileName + ".xls");
using (XmlTextWriter x = new XmlTextWriter(Response.OutputStream, Encoding.UTF8)) {
int sheetNumber = 0;
x.WriteRaw("<?xml version=\"1.0\"?><?mso-application progid=\"Excel.Sheet\"?>");
x.WriteRaw("<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" ");
x.WriteRaw("xmlns:o=\"urn:schemas-microsoft-com:office:office\" ");
x.WriteRaw("xmlns:x=\"urn:schemas-microsoft-com:office:excel\">");
x.WriteRaw("<Styles><Style ss:ID='sText'>" +
"<NumberFormat ss:Format='@'/></Style>");
x.WriteRaw("<Style ss:ID='sDate'><NumberFormat" +
" ss:Format='[$-409]m/d/yy\\ h:mm\\ AM/PM;@'/>");
x.WriteRaw("</Style></Styles>");
foreach (DataTable dt in tables) {
sheetNumber++;
string sheetName = !string.IsNullOrEmpty(dt.TableName) ?
dt.TableName : "Sheet" + sheetNumber.ToString();
x.WriteRaw("<Worksheet ss:Name='" + sheetName + "'>");
x.WriteRaw("<Table>");
string[] columnTypes = new string[dt.Columns.Count];
for (int i = 0; i < dt.Columns.Count; i++) {
string colType = dt.Columns[i].DataType.ToString().ToLower();
if (colType.Contains("datetime")) {
columnTypes[i] = "DateTime";
x.WriteRaw("<Column ss:StyleID='sDate'/>");
} else if (colType.Contains("string")) {
columnTypes[i] = "String";
x.WriteRaw("<Column ss:StyleID='sText'/>");
} else {
x.WriteRaw("<Column />");
if (colType.Contains("boolean")) {
columnTypes[i] = "Boolean";
} else {
//default is some kind of number.
columnTypes[i] = "Number";
}
}
}
//column headers
x.WriteRaw("<Row>");
foreach (DataColumn col in dt.Columns) {
x.WriteRaw("<Cell ss:StyleID='sText'><Data ss:Type='String'>");
x.WriteRaw(col.ColumnName);
x.WriteRaw("</Data></Cell>");
}
x.WriteRaw("</Row>");
//data
bool missedNullColumn = false;
foreach (DataRow row in dt.Rows) {
x.WriteRaw("<Row>");
for (int i = 0; i < dt.Columns.Count; i++) {
if (!row.IsNull(i)) {
if (missedNullColumn) {
int displayIndex = i + 1;
x.WriteRaw("<Cell ss:Index='" + displayIndex.ToString() +
"'><Data ss:Type='" +
columnTypes[i] + "'>");
missedNullColumn = false;
} else {
x.WriteRaw("<Cell><Data ss:Type='" +
columnTypes[i] + "'>");
}
switch (columnTypes[i]) {
case "DateTime":
x.WriteRaw(((DateTime)row[i]).ToString("s"));
break;
case "Boolean":
x.WriteRaw(((bool)row[i]) ? "1" : "0");
break;
case "String":
x.WriteString(row[i].ToString());
break;
default:
x.WriteString(row[i].ToString());
break;
}
x.WriteRaw("</Data></Cell>");
} else {
missedNullColumn = true;
}
}
x.WriteRaw("</Row>");
}
x.WriteRaw("</Table></Worksheet>");
}
x.WriteRaw("</Workbook>");
}
Response.End();
}
历史
- 2009 年 1 月 7 日:添加了关于导入的链接(请参阅简介)。
- 2009 年 1 月 8 日:更新了关于导入的链接(请参阅简介)。
- 2009 年 1 月 21 日:添加了关于服务器上不需要 Excel 的说明