我即将向ASP.NET应用程序添加一个部分(VB.NET代码隐藏),允许用户将数据作为Excel文件返回给它们,我将根据数据库数据生成该文件。虽然有几种方法可以做到这一点,但每种方法都有其自身的缺点。 你将如何返回数据?我正在寻找尽可能干净和简单的东西。
答案 0 :(得分:130)
优点:
缺点:
优点:
缺点:
优点:
缺点:
优点:
缺点:
优点:
缺点:
优点:
缺点:
答案 1 :(得分:38)
您可以将数据输出为html表格单元格,在其上添加.xls
或.xlsx
扩展名,Excel将打开它,就像它是本机文档一样。您甚至可以通过这种方式进行有限的格式化和公式计算,因此它比CSV更强大。此外,从ASP.Net等网络平台输出html表应该很容易;)
如果在Excel工作簿中需要多个工作表或命名工作表,则可以通过名为SpreadSheetML
的XML模式执行类似的操作。这是不 Office 2007附带的新格式,但是与Excel 2000一样完全不同的东西。解释它如何工作的最简单方法是使用示例:
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Author>Your_name_here</Author>
<LastAuthor>Your_name_here</LastAuthor>
<Created>20080625</Created>
<Company>ABC Inc</Company>
<Version>10.2625</Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>6135</WindowHeight>
<WindowWidth>8445</WindowWidth>
<WindowTopX>240</WindowTopX>
<WindowTopY>120</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom" />
<Borders />
<Font />
<Interior />
<NumberFormat />
<Protection />
</Style>
</Styles>
<Worksheet ss:Name="Sample Sheet 1">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table1">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
<Cell><Data ss:Type="Number">1</Data></Cell>
<Cell><Data ss:Type="Number">2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">3</Data></Cell>
<Cell><Data ss:Type="Number">4</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">5</Data></Cell>
<Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">7</Data></Cell>
<Cell><Data ss:Type="Number">8</Data></Cell>
</Row>
</Table>
</Worksheet>
<Worksheet ss:Name="Sample Sheet 2">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table2">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
<Cell><Data ss:Type="String">A</Data></Cell>
<Cell><Data ss:Type="String">B</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">C</Data></Cell>
<Cell><Data ss:Type="String">D</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">E</Data></Cell>
<Cell><Data ss:Type="String">F</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">G</Data></Cell>
<Cell><Data ss:Type="String">H</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook>
答案 2 :(得分:16)
如果来自 DataTable :
public static void DataTabletoXLS(DataTable DT, string fileName)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-16";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.xls", fileName));
HttpContext.Current.Response.ContentType = "application/ms-excel";
string tab = "";
foreach (DataColumn dc in DT.Columns)
{
HttpContext.Current.Response.Write(tab + dc.ColumnName.Replace("\n", "").Replace("\t", ""));
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
int i;
foreach (DataRow dr in DT.Rows)
{
tab = "";
for (i = 0; i < DT.Columns.Count; i++)
{
HttpContext.Current.Response.Write(tab + dr[i].ToString().Replace("\n", "").Replace("\t", ""));
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
}
HttpContext.Current.Response.End();
}
来自 Gridview :
public static void GridviewtoXLS(GridView gv, string fileName)
{
int DirtyBit = 0;
int PageSize = 0;
if (gv.AllowPaging == true)
{
DirtyBit = 1;
PageSize = gv.PageSize;
gv.AllowPaging = false;
gv.DataBind();
}
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Charset = "utf-8";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}.xls", fileName));
HttpContext.Current.Response.ContentType = "application/ms-excel";
using (StringWriter sw = new StringWriter())
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// Create a table to contain the grid
Table table = new Table();
// include the gridline settings
table.GridLines = gv.GridLines;
// add the header row to the table
if (gv.HeaderRow != null)
{
Utilities.Export.PrepareControlForExport(gv.HeaderRow);
table.Rows.Add(gv.HeaderRow);
}
// add each of the data rows to the table
foreach (GridViewRow row in gv.Rows)
{
Utilities.Export.PrepareControlForExport(row);
table.Rows.Add(row);
}
// add the footer row to the table
if (gv.FooterRow != null)
{
Utilities.Export.PrepareControlForExport(gv.FooterRow);
table.Rows.Add(gv.FooterRow);
}
// render the table into the htmlwriter
table.RenderControl(htw);
// render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString().Replace("£", ""));
HttpContext.Current.Response.End();
}
if (DirtyBit == 1)
{
gv.PageSize = PageSize;
gv.AllowPaging = true;
gv.DataBind();
}
}
private static void PrepareControlForExport(Control control)
{
for (int i = 0; i < control.Controls.Count; i++)
{
Control current = control.Controls[i];
if (current is LinkButton)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as LinkButton).Text));
}
else if (current is ImageButton)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as ImageButton).AlternateText));
}
else if (current is HyperLink)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as HyperLink).Text));
}
else if (current is DropDownList)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as DropDownList).SelectedItem.Text));
}
else if (current is CheckBox)
{
control.Controls.Remove(current);
control.Controls.AddAt(i, new LiteralControl((current as CheckBox).Checked ? "True" : "False"));
}
if (current.HasControls())
{
Utilities.Export.PrepareControlForExport(current);
}
}
}
答案 3 :(得分:7)
这是一个围绕SpreadML的免费包装器 - 它运行良好。
答案 4 :(得分:5)
根据给出的答案以及与同事的协商,最佳解决方案似乎是生成XML文件或HTML表格并将其作为附件下推。我的同事推荐的一个改变是数据(即HTML表)可以直接写入Response对象,因此无需写出文件,由于权限问题,I / O可能会很麻烦争用,并确保发生计划的清除。
这是代码的片段......我还没有检查过这个,我还没有提供所有被调用的代码,但我认为它代表了这个想法。
Dim uiTable As HtmlTable = GetUiTable(groupedSumData)
Response.Clear()
Response.ContentType = "application/vnd.ms-excel"
Response.AddHeader("Content-Disposition", String.Format("inline; filename=OSSummery{0:ddmmssf}.xls", DateTime.Now))
Dim writer As New System.IO.StringWriter()
Dim htmlWriter As New HtmlTextWriter(writer)
uiTable.RenderControl(htmlWriter)
Response.Write(writer.ToString)
Response.End()
答案 5 :(得分:4)
由于Excel理解HTML,您只需将数据作为HTML表格写入扩展名为.xls的临时文件,获取文件的FileInfo,然后使用
将其重新打开。Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + fi.Name);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(fi.FullName);
Response.End();
如果你想避开临时文件,你可以写入内存中的流并写回字节而不是使用WriteFile
如果省略了content-length标题,你可以直接写回html,但这可能无法在所有浏览器中一直正常工作
答案 6 :(得分:3)
我个人更喜欢XML方法。我将从数据集中的数据库中返回数据,将其保存到XMl,然后创建一个xslt文件,其中包含将格式化正确文档的转换规则,并且简单的XML转换将完成作业。关于此的最佳部分,您可以格式化单元格,进行条件格式设置,设置页眉和页脚,甚至设置打印范围。
答案 7 :(得分:2)
我们始终将数据从数据网格导出为excel。将其转换为HTML然后写入excel文件
Response.ContentType = "application/vnd.ms-excel"
Response.Charset = ""
Response.AddHeader("content-disposition", "fileattachment;filename=YOURFILENAME.xls")
Me.EnableViewState = False
Dim sw As System.IO.StringWriter = New System.IO.StringWriter
Dim hw As HtmlTextWriter = New HtmlTextWriter(sw)
ClearControls(grid)
grid.RenderControl(hw)
Response.Write(sw.ToString())
Response.End()
这种方法唯一的问题是我们的很多网格都有按钮或链接,所以你也需要它:
'needed to export grid to excel to remove link button control and represent as text
Private Sub ClearControls(ByVal control As Control)
Dim i As Integer
For i = control.Controls.Count - 1 To 0 Step -1
ClearControls(control.Controls(i))
Next i
If TypeOf control Is System.Web.UI.WebControls.Image Then
control.Parent.Controls.Remove(control)
End If
If (Not TypeOf control Is TableCell) Then
If Not (control.GetType().GetProperty("SelectedItem") Is Nothing) Then
Dim literal As New LiteralControl
control.Parent.Controls.Add(literal)
Try
literal.Text = CStr(control.GetType().GetProperty("SelectedItem").GetValue(control, Nothing))
Catch
End Try
control.Parent.Controls.Remove(control)
Else
If Not (control.GetType().GetProperty("Text") Is Nothing) Then
Dim literal As New LiteralControl
control.Parent.Controls.Add(literal)
literal.Text = CStr(control.GetType().GetProperty("Text").GetValue(control, Nothing))
control.Parent.Controls.Remove(control)
End If
End If
End If
Return
End Sub
我发现在某处,它运作良好。
答案 8 :(得分:2)
我已经完成了几次,每次最简单的方法就是返回一个CSV(逗号分隔值)文件。 Excel完美地导入它,并且它的速度相对较快。
答案 9 :(得分:2)
我推荐基于OpenXML的free opensource excel generation libruary
几个月前它帮助了我。答案 10 :(得分:2)
这是一个从存储过程中提取的报告。结果将导出到Excel。 它使用ADO而不是ADO.NET,原因是这一行
oSheet.Cells(2, 1).copyfromrecordset(rst1)
它执行大部分工作,但在ado.net中不可用。
‘Calls stored proc in SQL Server 2000 and puts data in Excel and ‘formats it
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim cnn As ADODB.Connection
cnn = New ADODB.Connection
cnn.Open("Provider=SQLOLEDB;data source=xxxxxxx;" & _
"database=xxxxxxxx;Trusted_Connection=yes;")
Dim cmd As New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandText = "[sp_TomTepley]"
cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
cmd.CommandTimeout = 0
cmd.Parameters.Refresh()
Dim rst1 As ADODB.Recordset
rst1 = New ADODB.Recordset
rst1.Open(cmd)
Dim oXL As New Excel.Application
Dim oWB As Excel.Workbook
Dim oSheet As Excel.Worksheet
'oXL = CreateObject("excel.application")
oXL.Visible = True
oWB = oXL.Workbooks.Add
oSheet = oWB.ActiveSheet
Dim Column As Integer
Column = 1
Dim fld As ADODB.Field
For Each fld In rst1.Fields
oXL.Workbooks(1).Worksheets(1).Cells(1, Column).Value = fld.Name
oXL.Workbooks(1).Worksheets(1).cells(1, Column).Interior.ColorIndex = 15
Column = Column + 1
Next fld
oXL.Workbooks(1).Worksheets(1).name = "Tom Tepley Report"
oSheet.Cells(2, 1).copyfromrecordset(rst1)
oXL.Workbooks(1).Worksheets(1).Cells.EntireColumn.AutoFit()
oXL.Visible = True
oXL.UserControl = True
rst1 = Nothing
cnn.Close()
Beep()
End Sub
答案 11 :(得分:1)
您可以使用此库轻松创建格式精美的Excel文件:http://officehelper.codeplex.com/documentation。
不需要在网络服务器上安装Microsoft Office!
答案 12 :(得分:1)
通过Microsoft.Office.Interop命名空间避免COM Interop。它是如此缓慢,不可靠和不可扩展。不适用于受虐狂者。
答案 13 :(得分:1)
如果用数据填充GridView,可以使用此函数获取HTML格式的数据,但指示浏览器是excel文件。
Public Sub ExportToExcel(ByVal fileName As String, ByVal gv As GridView)
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
HttpContext.Current.Response.ContentType = "application/ms-excel"
Dim sw As StringWriter = New StringWriter
Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
Dim table As Table = New Table
table.GridLines = gv.GridLines
If (Not (gv.HeaderRow) Is Nothing) Then
PrepareControlForExport(gv.HeaderRow)
table.Rows.Add(gv.HeaderRow)
End If
For Each row As GridViewRow In gv.Rows
PrepareControlForExport(row)
table.Rows.Add(row)
Next
If (Not (gv.FooterRow) Is Nothing) Then
PrepareControlForExport(gv.FooterRow)
table.Rows.Add(gv.FooterRow)
End If
table.RenderControl(htw)
HttpContext.Current.Response.Write(sw.ToString)
HttpContext.Current.Response.End()
End Sub
Private Sub PrepareControlForExport(ByVal control As Control)
Dim i As Integer = 0
Do While (i < control.Controls.Count)
Dim current As Control = control.Controls(i)
If (TypeOf current Is LinkButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, LinkButton).Text))
ElseIf (TypeOf current Is ImageButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, ImageButton).AlternateText))
ElseIf (TypeOf current Is HyperLink) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, HyperLink).Text))
ElseIf (TypeOf current Is DropDownList) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, DropDownList).SelectedItem.Text))
ElseIf (TypeOf current Is CheckBox) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New LiteralControl(CType(current, CheckBox).Checked))
End If
If current.HasControls Then
PrepareControlForExport(current)
End If
i = i + 1
Loop
End Sub
答案 14 :(得分:0)
我使用上面提到的与this answer类似的解决方案之一遇到的一个问题是,如果您将内容作为附件推出(我发现这是最干净的解决方案)对于非ms浏览器),然后在Excel 2000-2003中打开它,它的类型是“Excel网页”而不是本机Excel文档。
然后,您必须向用户解释如何使用Excel中的“另存为类型”将其转换为Excel文档。如果用户需要编辑此文档,然后将其重新上传到您的网站,则会很麻烦。
我的建议是使用CSV。这很简单,如果用户在Excel中打开它,Excel至少会提示他们以原生格式保存它。
答案 15 :(得分:0)
这是一个将数据流作为CSV流出的解决方案。快速,干净,简单,它在输入中处理逗号。
public static void ExportToExcel(DataTable data, HttpResponse response, string fileName)
{
response.Charset = "utf-8";
response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.ContentType = "text/csv";
response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
for (int i = 0; i < data.Columns.Count; i++)
{
response.Write(data.Columns[i].ColumnName);
response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
}
foreach (DataRow row in data.Rows)
{
for (int i = 0; i < data.Columns.Count; i++)
{
response.Write(String.Format("\"{0}\"", row[i].ToString()));
response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
}
}
response.End();
}
答案 16 :(得分:0)
CSV是最简单的方法。大部分时间它都链接到Excel。否则,您必须使用自动化API或XML格式。 API和XML并不难以使用。
答案 17 :(得分:0)
您当然可以选择第三方组件。就个人而言,我对Spire.XLS有http://www.e-iceblue.com/xls/xlsintro.htm
的良好体验该组件在您的应用程序中非常易于使用:
Workbook workbook = new Workbook();
//Load workbook from disk.
workbook.LoadFromFile(@"Data\EditSheetSample.xls");
//Initailize worksheet
Worksheet sheet = workbook.Worksheets[0];
//Writes string
sheet.Range["B1"].Text = "Hello,World!";
//Writes number
sheet.Range["B2"].NumberValue = 1234.5678;
//Writes date
sheet.Range["B3"].DateTimeValue = System.DateTime.Now;
//Writes formula
sheet.Range["B4"].Formula = "=1111*11111";
workbook.SaveToFile("Sample.xls");
答案 18 :(得分:0)
假设这是一个内部网,您可以在其中设置权限并强制执行IE,您可以使用JScript/VBScript driving Excel生成工作簿客户端。这为您提供了原生的Excel格式,没有尝试在服务器上自动化Excel的麻烦。
我不确定我是否真的会推荐这种方法,除非在相当小的情况下,但在经典的ASP鼎盛时期它是相当普遍的。
答案 19 :(得分:0)
我见过的excel报告的最佳方法是使用XML扩展以XML格式写出数据并将其流式传输到具有正确内容类型的客户端。 (应用/ XLS)
这适用于任何需要基本格式化的报告,并允许您使用文本比较工具与现有电子表格进行比较。
答案 20 :(得分:0)
避免“看起来这些数字存储为文本”绿色三角形的唯一防弹方法是使用Open XML格式。值得使用它,只是为了避免不可避免的绿色三角形。
答案 21 :(得分:0)
man,在.net中我想你可以有一个组件可以做到这一点,但在经典的asp我已经完成了创建一个html表并将页面的mime tipe更改为vnd / msexcel。我想如果你使用gridview并更改mime类型,它可能会起作用,因为gridview是一个html表。
答案 22 :(得分:0)
我要么采用CSV路由(如上所述),要么更常见,我使用Infragistics NetAdvantage生成文件。 (在Infragistics正在运行的绝大多数时间里,我们只是导出一个现有的UltraWebGrid,它本质上是一个LOC解决方案,除非需要额外的格式调整。我们也可以手动生成Excel / BIFF文件,但很少需要。)
答案 23 :(得分:0)
我只是根据数据创建一个CSV文件,因为我认为它是最干净的,Excel对它有很好的支持。但是如果你需要更灵活的格式,我相信有一些第三方工具可以生成真正的excel文件。
答案 24 :(得分:-1)
刚刚创建了一个从Web表单C#导出到excel希望它能帮助其他人的功能
public void ExportFileFromSPData(string filename, DataTable dt)
{
HttpResponse response = HttpContext.Current.Response;
//clean up the response.object
response.Clear();
response.Buffer = true;
response.Charset = "";
// set the response mime type for html so you can see what are you printing
//response.ContentType = "text/html";
//response.AddHeader("Content-Disposition", "attachment;filename=test.html");
// set the response mime type for excel
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
response.ContentEncoding = System.Text.Encoding.UTF8;
response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble());
//style to format numbers to string
string style = @"<style> .text { mso-number-format:\@; } </style>";
response.Write(style);
// create a string writer
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// instantiate a datagrid
GridView dg = new GridView();
dg.DataSource = dt;
dg.DataBind();
foreach (GridViewRow datarow in dg.Rows)
{
//format specific cell to be text
//to avoid 1.232323+E29 to get 1232312312312312124124
datarow.Cells[0].Attributes.Add("class", "text");
}
dg.RenderControl(htw);
response.Write(sw.ToString());
response.End();
}
}
}
答案 25 :(得分:-5)
如果必须使用Excel而不是CSV文件,则需要在服务器上的Excel实例上使用OLE自动化。最简单的方法是使用模板文件并以编程方式将其填入数据中。您将其保存到另一个文件。
提示:
如果您不介意文件的格式有点基本,那么某些'使用mime-types来欺骗打开HTML表的方法'会有效。这些方法还可以将CPU繁重的工作转移到客户端上。如果您希望对电子表格的格式进行精细控制,则可能必须使用Excel本身来生成如上所述的文件。