65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 从 Gridview 和 Datareader 导出大型数据到 Excel 文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (24投票s)

2007年6月21日

5分钟阅读

viewsIcon

264853

downloadIcon

3927

一篇关于将大型数据导出到 Excel 文件的文章。

Screenshot - ExportLargeDataInExcel.jpg

引言

显示数据的良好方式是将其显示在网格视图中。然而,以这种方式处理和筛选大量数据变得困难。将数据导出到 Excel 文件是处理大量数据的绝佳解决方案,因为 Excel 具有许多功能——例如排序、搜索和筛选——而无需您编写一行代码。在此示例中,我将展示

  1. 如何从数据库中提取数据并在网格中显示它。
  2. 如何将数据从网格导出到 Excel 文件。
  3. 如何将数据从数据读取器导出到 Excel 文件。
  4. 如何处理大量数据并应对不同类型的错误。

使用代码

此示例使用 ASP.NET 2.0、C# 和 SQL Server 2005。我使用了简单的数据库表形式,以避免不必要的开销。假设我们有一个名为 UniversityManager 的数据库,其中有一个名为 Student 的表。表的结构如下

列名 数据类型
Roll(滚动) varchar(10)
名称 varchar(50)
分数 int

我正在使用 ASP.NET SqlDataSource 控件从数据库中提取数据。SqlDataSource 可以用作可以从数据库中获取数据的源。它可以绑定到 ASP.NET 控件。为了在网格中显示这些数据,我使用了 ASP.NET GridView 控件。GridView 控件是 DataGrid 控件的后继。与 DataGrid 控件一样,GridView 控件设计用于在 HTML 表中显示数据。当绑定到数据源时,DataGridGridView 控件都会将 DataSource 的一行显示为输出表的一行。ASP 端代码如下

<asp:GridView ID="grdStudentMarks" runat="server" 
    DataSourceID="dsStudentMarks">
    <EmptyDataTemplate>
        No Data Found
    </EmptyDataTemplate>
    <RowStyle CssClass="ClsOddRow" />
    <AlternatingRowStyle CssClass="ClsEvenRow" />
    <HeaderStyle CssClass="ClsHeaderRow" /> 
</asp:GridView>

<asp:SqlDataSource ID="dsStudentMarks" runat="server" ConnectionString=
  "Data Source=.;Initial Catalog=UniversityManager;Integrated Security=True;"
    SelectCommand="
    (
        SELECT *FROM STUDENT 
    ) 
    "> 
</asp:SqlDataSource>

<asp:Button ID="btnExportFromDatagrid" runat="server" 
    Text="Export From Grid" OnClick="btnExportFromDatagrid_Click" />

<asp:Button ID="btnExportFromDataset" runat="server" 
    Text="Export From Data set" />

当 ASP.NET 页面渲染时,grdStudentMarks 将由 UniversityManager 数据库的 Student 表中的数据填充。因此,使用了 Windows 身份验证。除此之外,我还添加了两个名为 btnExportFromDatagridbtnExportFromDataset 的按钮。现在我们有一个包含数据库数据的网格。我们的下一个目标是将此数据从数据网格导出到 Excel。我们在 btnExportFromDataGrid 的 Click 事件中编写了此代码。

protected void btnExportFromDatagrid_Click(object sender, EventArgs e)
    {
        ExportGridToExcel(grdStudentMarks, "StudentMarks.xls");   
    }
    public void ExportGridToExcel(GridView grdGridView, string fileName)
    {
        Response.Clear();
        Response.AddHeader("content-disposition", 
            string.Format("attachment;filename={0}.xls", fileName));
        Response.Charset = "";
        Response.ContentType = "application/vnd.xls";

        StringWriter stringWrite = new StringWriter();
        HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
        grdGridView.RenderControl(htmlWrite);
        Response.Write(stringWrite.ToString());
        Response.End();
    }

当按钮被点击时,我们调用函数 ExportGridToExcel,并将参数设置为 Gridview 和我们希望保存的文件名。在 HttpResponse 流中添加了一个标题。它将强制用户下载文件,而不是在浏览器中内嵌显示。然后,我们使用 Response.ContentType 将输出流的 HTTP MIME 类型设置为 *application/vnd.xls*。然后使用 GridView 类的 RenderControl 方法,该方法将服务器控件内容输出到提供的 HtmlTextWriter htmlWrite。最后,将其写入 Response 流。

此时工作应该完成了!然而,如果您加载页面并单击按钮,您可能会看到以下错误

类型为“GridView”的控件“grdStudentMarks”必须放置在具有 runat=server 的 form 标签内。

要解决此错误,您应该重写 VerifyRenderingInServerForm 方法。只需编写以下代码

public override void VerifyRenderingInServerForm(Control control)
    {

    }

就是这样!网格视图的数据将被导出到 Excel 文件,该文件应保存在桌面。然而,这个解决方案存在一些问题。首先,如果您的网格视图使用分页,那么只有单个页面的数据将被导出,而不是整个网格的数据。这意味着只有页面内渲染的数据才会被导出。其次,如果网格视图的数据量很大,您可能会遇到以下错误

超时已过期。在操作完成之前,超时时间已到期,或者服务器未响应。

这是一个 System.Data.SqlClient.SqlException。当操作完成之前超时时间已到期时,就会发生此异常。因此,要解决此类问题,我们将使用以下解决方案。

超时解决方案

我将使用 SQLCommand 类,因为通过使用它,我们可以设置超时属性。CommandTimeout 属性设置在终止任何执行命令之前的等待时间。数据被读入 SqlDataReader,数据读取器的每一行都被写入 Response 流。需要注意的是,每个单元格的值——即一行中的特定列——后面都跟着一个逗号分隔符,以便 CSV 文件可以格式化它。代码如下

protected void btnExportFromDataset_Click(object sender, EventArgs e)
{
    ExportToExcel(dsStudentMarks, "StudentMarks");
}
 
public void ExportToExcel(SqlDataSource dataSrc, string fileName)
{
    //Add Response header 
    Response.Clear();
    Response.AddHeader("content-disposition", 
        string.Format("attachment;filename={0}.csv", fileName));
    Response.Charset = "";
    Response.ContentType = "application/vnd.xls";
    //GET Data From Database                
    SqlConnection cn = new SqlConnection(dataSrc.ConnectionString);
    string query = 
        dataSrc.SelectCommand.Replace("\r\n", " ").Replace("\t", " ");
        
    SqlCommand cmd = new SqlCommand(query, cn);
        
    cmd.CommandTimeout = 999999 ;
    cmd.CommandType    = CommandType.Text;
    try
    {
        cn.Open();
        SqlDataReader dr = cmd.ExecuteReader();
        StringBuilder sb = new StringBuilder();            
        //Add Header          
        for (int count = 0; count < dr.FieldCount; count++)
        {
            if (dr.GetName(count) != null)
                sb.Append(dr.GetName(count));
            if (count < dr.FieldCount - 1)
            {
                sb.Append(",");
            }
        }
        Response.Write(sb.ToString() + "\n");
        Response.Flush();            
        //Append Data
        while (dr.Read())
        {
            sb = new StringBuilder();
               
            for (int col = 0; col < dr.FieldCount - 1; col++)
            {
                if (!dr.IsDBNull(col))
                    sb.Append(dr.GetValue(col).ToString().Replace(",", " "));
                    sb.Append(",");
            }
            if (!dr.IsDBNull(dr.FieldCount - 1))
                sb.Append(dr.GetValue(
                dr.FieldCount - 1).ToString().Replace(",", " "));
            Response.Write(sb.ToString() + "\n");
            Response.Flush();
        }
        dr.Dispose();
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
    }
    finally
    {
        cmd.Connection.Close();
        cn.Close();
    }
    Response.End();
}

这解决了下载大量数据的问题。

SQLClient 超时异常的问题现已解决,但仍有可能出现 HttpRequest 超时异常。要解决此问题,请在 *web.config* 文件的 <system.web> 标签内放入以下行

<httpRuntime maxRequestLength="209715" executionTimeout="3600" />

就是这样!

关注点

因此,我们学习了如何从数据库中提取数据并在网格视图控件中显示它。我们学习了如何将数据从网格视图导出到 Excel 文件,如何从数据读取器导出大量数据以及如何将这些数据导出到 Excel 文件。我希望这个例子能帮助您。对于本篇文章,请随时给我任何建议。编码愉快!

历史

此演示首次上传于 2007 年 6 月 21 日。

© . All rights reserved.