zoukankan      html  css  js  c++  java
  • DataSet导出到Excel比较完整的解决方案(二)服务器端生成文件(downmoon)

    前一篇文章中,介绍了DataSet导出到Excel时客户端生成文件的几种思路,接着往下说,服务器端生成文件,用户直接下载,应该格式是可以保证的!

    于是直接调用Excel的API生成。代码如下:


     public static void DataSetToLocalExcel(DataSet dataSet, string outputPath, bool deleteOldFile)
            
    {
                
    if (deleteOldFile)
                
    {
                    
    if (System.IO.File.Exists(outputPath)) { System.IO.File.Delete(outputPath); }
                }

                
    // Create the Excel Application object
                ApplicationClass excelApp = new ApplicationClass();

                
    // Create a new Excel Workbook
                Workbook excelWorkbook = excelApp.Workbooks.Add(Type.Missing);

                
    int sheetIndex = 0;

                
    // Copy each DataTable
                foreach (System.Data.DataTable dt in dataSet.Tables)
                
    {

                    
    // Copy the DataTable to an object array
                    object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];

                    
    // Copy the column names to the first row of the object array
                    for (int col = 0; col < dt.Columns.Count; col++)
                    
    {
                        rawData[
    0, col] = dt.Columns[col].ColumnName;
                    }


                    
    // Copy the values to the object array
                    for (int col = 0; col < dt.Columns.Count; col++)
                    
    {
                        
    for (int row = 0; row < dt.Rows.Count; row++)
                        
    {
                            rawData[row 
    + 1, col] = dt.Rows[row].ItemArray[col];
                        }

                    }


                    
    // Calculate the final column letter
                    string finalColLetter = string.Empty;
                    
    string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                    
    int colCharsetLen = colCharset.Length;

                    
    if (dt.Columns.Count > colCharsetLen)
                    
    {
                        finalColLetter 
    = colCharset.Substring(
                            (dt.Columns.Count 
    - 1/ colCharsetLen - 11);
                    }


                    finalColLetter 
    += colCharset.Substring(
                            (dt.Columns.Count 
    - 1% colCharsetLen, 1);

                    
    // Create a new Sheet
                    Worksheet excelSheet = (Worksheet)excelWorkbook.Sheets.Add(
                        excelWorkbook.Sheets.get_Item(
    ++sheetIndex),
                        Type.Missing, 
    1, XlSheetType.xlWorksheet);

                    excelSheet.Name 
    = dt.TableName;

                    
    // Fast data export to Excel
                    string excelRange = string.Format("A1:{0}{1}",
                        finalColLetter, dt.Rows.Count 
    + 1);

                    excelSheet.get_Range(excelRange, Type.Missing).Value2 
    = rawData;

                    
    // Mark the first row as BOLD
                    ((Range)excelSheet.Rows[1, Type.Missing]).Font.Bold = true;
                }

                
    //excelApp.Application.AlertBeforeOverwriting = false;
                excelApp.Application.DisplayAlerts = false;
                
    // Save and Close the Workbook
                excelWorkbook.SaveAs(outputPath, XlFileFormat.xlWorkbookNormal, Type.Missing,
                    Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive,
                    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
                excelWorkbook.Close(
    true, Type.Missing, Type.Missing);
                excelWorkbook 
    = null;

                
    // Release the Application object
                excelApp.Quit();
                excelApp 
    = null;

                
    // Collect the unreferenced objects
                GC.Collect();
                GC.WaitForPendingFinalizers();

            }

    说明下,其中的  xlsApp.Application.DisplayAlerts   =   false;  的作用是不显示确认对话框    

    也可以逐Cell读取,那样可能会慢。本方法速度还过得去。

    生成Winform代码测试没错,部署时,以为只要引用两个dll就可以了

    Microsoft.Office.Interop.Excel.dll

    Office.dll


    那成想,问题接着来了,当在WebForm下调用时, 提示“检索   COM   类工厂中   CLSID   为   {00024500-0000-0000-C000-000000000046}   的组件时失败,原因是出现以下错误:   8000401a

    晕! Google下,解决方案是在服务器上安装Office,并配置DCOM权限。步骤如下:


    配置  DCOM  中  EXCEL  应用程序:
    要在交互式用户帐户下设置  Office  自动化服务器,请按照下列步骤操作: 
    1.  以管理员身份登录到计算机,并使用完整安装来安装(或重新安装)Office。为了实现系统的可靠性,建议您将  Office  CD-ROM  中的内容复制到本地驱动器并从此位置安装  Office。 
    2.  启动要自动运行的  Office  应用程序。这会强制该应用程序进行自我注册。 
    3.  运行该应用程序后,请按  Alt+F11  以加载  Microsoft  Visual  Basic  for  Applications  (VBA)  编辑器。这会强制  VBA  进行初始化。 
    4.  关闭应用程序,包括  VBA。 
    5.  单击开始,单击运行,然后键入  DCOMCNFG。选择要自动运行的应用程序。应用程序名称如下所示: 
    Microsoft  Access  97  -  Microsoft  Access  数据库
    Microsoft  Access  2000/2002  -  Microsoft  Access  应用程序
    Microsoft  Excel  97/2000/2002  -  Microsoft  Excel  应用程序
    Microsoft  Word  97  -  Microsoft  Word  Basic
    Microsoft  Word  2000/2002  -  Microsoft  Word  文档 
    单击属性打开此应用程序的属性对话框。
    6.  单击安全选项卡。验证使用默认的访问权限和使用默认的启动权限已选中。 
    7.  单击标识选项卡,然后选择交互式用户。 
    8.  单击确定,关闭属性对话框并返回主应用程序列表对话框。 
    9.  在  DCOM  配置对话框中,单击默认安全性选项卡。 
    10.  单击访问权限的编辑默认值。验证访问权限中是否列出下列用户,如果没有列出,则添加这些用户: 
    SYSTEM
    INTERACTIVE
    Everyone
    Administrators
    IUSR_ 
    <machinename> *
    IWAM_ 
    <machinename> *
    *  这些帐户仅在计算机上安装了  Internet  Information  Server  (IIS)  的情况下才存在。 
    11.  确保允许每个用户访问,然后单击确定。 
    12.  单击启动权限的编辑默认值。验证启动权限中是否列出下列用户,如果没有列出,则添加这些用户: 
    SYSTEM
    INTERACTIVE
    Everyone
    Administrators
    IUSR_ 
    <machinename> *
    IWAM_ 
    <machinename> *
    *  这些帐户仅在计算机上安装有  IIS  的情况下才存在。 
    13.  确保允许每个用户访问,然后单击确定。 
    14.  单击确定关闭  DCOMCNFG。 
    如果你之前起用了身份模拟  (在  web.config  中配置了  
    <identity  impersonate= "true "/>  )  ,需要删除之! 
    15.更新安装office,把.net可编程组件安装到本机(excel组件)
    如果还是不行.干脃把交互式用户 换成"启动用户" 

     
    折腾了一番,总算可以用了!·只是服务器上装Office总感觉不爽,于是再尝试下别的方法:

    Reading and Writing Excel using OLEDB

    主要的类文件如下:

     /// <summary>
        
    /// Summary description for ExcelReader.
        
    /// </summary>

        public class ExcelReader : IDisposable
        
    {
            
    Variables

            
    properties

            
    Methods

            
    public

            
    Dispose / Destructor

            
    CTOR
        }

    思路:通过读出Excel模板文件到DataTale,再把数据填充到DataTable,文件另存下就OK了!

     调用代码如下:


     public static string path = @"TempExcel\STemp.xls";
            
    public static string path2 = "TestUser.xls";
            
    public static string PreFilePath = @"C:\Excel\";
            
    public static void DataSetToLocalExcel(DataSet ds, string srcPath, string outputPath, bool deleteOldFile)
            
    {
                
    if (ds == null || ds.Tables[0== null && ds.Tables[0].Rows.Count == 0return; }
                
    if (deleteOldFile)
                
    {
                    
    if (System.IO.File.Exists(outputPath)) { System.IO.File.Delete(outputPath); }
                }

                System.IO.File.Copy(srcPath, outputPath, 
    true);
                ExcelReader exr 
    = new ExcelReader();
                exr.ExcelFilename 
    = outputPath;
                exr.Headers 
    = true;
                exr.MixedData 
    = true;
                exr.KeepConnectionOpen 
    = true;
                
    string[] sheetnames = exr.GetExcelSheetNames();
                exr.SheetName 
    = sheetnames[0];
                DataTable dt 
    = exr.GetTable();
                
    if (dt == nullreturn;
                exr.SetPrimaryKey(
    0);
                
    //dt.PrimaryKey = new DataColumn[] { dt.Columns["编号"] };
                DataTable dt2 = ds.Tables[0].Copy();
                dt.Rows.Clear();
                
    for (int i = 0; i < dt2.Rows.Count; i++)
                
    // Copy the values to the object array
                    DataRow dr = dt.NewRow();
                    
    for (int col = 0; col < dt.Columns.Count; col++)
                    
    {
                        dr[col] 
    = dt2.Rows[i][col];
                    }

                    dt.Rows.Add(dr);
                }

                exr.SetTable(dt);
                
    #region WriteFile
               
                
    #endregion

                exr.Close();
                exr.Dispose();
                exr 
    = null;
            }

            
    private DataSet Get_AllPrices()
            
    {
                
    try
                
    {
                    
    // Get the employee details
                    string strSql = "SELECT [CustomID] as 编号,[C_Name] as 品名,0 as 最高价格,0 as 最低价格,0 as 平均价格,'元/公斤' as 计量单位,'' as 备注  FROM [PriceCategory] WHERE ( 1=1 AND ([Puser] = 'tuser') )";
                    SqlConnection objConn 
    = new SqlConnection(@"Data Source=AP6;Initial Catalog=testdb2009 ;Persist Security Info=True;User ID=sa;Password=sa");
                    SqlDataAdapter daEmp 
    = new SqlDataAdapter(strSql, objConn);
                    daEmp.Fill(dsPrice, 
    "price");
                    
    return dsPrice;
                }

                
    catch (Exception Ex)
                
    {
                    
    throw Ex;
                }

            }


            DataSet dsPrice 
    = new DataSet();
            
    protected void btnGetData_Click(object sender, EventArgs e)
            
    {
                DataSetToLocalExcel(Get_AllPrices(), PreFilePath 
    + path, PreFilePath + path2, true);
            }

     

    这里有点强调下:OleDbConnection特别要注意, 刚开始用http://www.connectionstrings.com/excel

      提供的标准串:

    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:"MyExcel.xls;Extended Properties="Excel 8.0;HDR=Yes;IMEX=1";

    结果提示:“操作必须使用一个可更新的查询”。因为读取结果正常,以为是excel没有写权限所致,增加了相应权限后,结果依然如故。这下火了! Google下, 有解决方案

    http://www.cnblogs.com/richinger/archive/2008/09/28/1301170.html

    A: HDR ( HeaDer Row )设置
        若指定值为Yes,代表 Excel 档中的工作表第一行是栏位名称

        若指定值為 No,代表 Excel 档中的工作表第一行就是資料了,沒有栏位名称

        B:IMEX ( IMport EXport mode )设置

         IMEX 有三种模式,各自引起的读写行为也不同,容後再述:
         0 is Export mode
         1 is Import mode
         2 is Linked mode (full update capabilities)

        

    于是修改为:


    Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:"MyExcel.xls;Extended Properties="Excel 8.0;HDR=Yes;IMEX=2";
  • 相关阅读:
    初賽
    SA
    高斯-约旦消元法
    AC自动机
    KMP
    关于scanf
    网络流
    常用SQL语句
    Java开发中的23种设计模式详解(转)
    generatorConfig.xml
  • 原文地址:https://www.cnblogs.com/liufei88866/p/1376765.html
Copyright © 2011-2022 走看看