.NET Excel導出方法及其常見問題詳解


摘要:.NET Excel導出方法及其常見問題詳解。

一、Excel導出的實現方法

  在.net 程序開發中,對於Excel文件的導出我們一共有三種導出方式:

  1. 利用文件輸出流進行讀寫操作

    這種方式的導出方法是比較簡單就可以實現的,我們實際上是針對類似於html中table表格的輸出

    a.針對想要的Excel合並樣式寫一個table標簽代碼

       

 1 <table border="1">
 2     <thead>
 3         <tr>
 4             <th style="background-color:yellow" colspan="7" align="center">物料匯總單</th>
 5         </tr>
 6         <tr>
 7             <th style="background-color:yellow">物料碼</th>
 8             <th style="background-color:yellow">物料名稱</th>
 9             <th style="background-color:yellow">型號</th>
10             <th style="background-color:yellow">單位</th>
11             <th style="background-color:yellow">數量</th>
12             <th style="background-color:yellow">備注</th>
13             <th style="background-color:yellow">排序</th>
14         </tr>
15     </thead>
16     <tbody>
17         <tr>
18             <th>{0}</th>
19             <th>{0}</th>
20             <th>{0}</th>
21             <th>{0}</th>
22             <th>{0}</th>
23             <th>{0}</th>
24             <th>{0}</th>
25         </tr>
26     </tbody>
27 </table>

    table的border屬性可以控制展現為Excel文件時是否顯示網格線,一般如果不設置為border="1"時,導出的文件是不會生成網格線的,實際上table的各種屬性和樣式最終在生成為Excel文件時,都大致會以相同的格式展現出來,也就是說我們只要設計好table的樣式就行,不用考慮其它的問題了。

    而對於表頭中的顏色設置:

1        <tr>
2             <th style="background-color:yellow">物料碼</th>
3             <th style="background-color:yellow">物料名稱</th>
4             <th style="background-color:yellow">型號</th>
5             <th style="background-color:yellow">單位</th>
6             <th style="background-color:yellow">數量</th>
7             <th style="background-color:yellow">備注</th>
8             <th style="background-color:yellow">排序</th>
9         </tr>    

    有不少人會疑惑:為什么不在<tr>設置background-color不是更方便?

1        <tr style="background-color:yellow">
2             <th>物料碼</th>
3             <th>物料名稱</th>
4             <th>型號</th>
5             <th>單位</th>
6             <th>數量</th>
7             <th>備注</th>
8             <th>排序</th>
9         </tr>

    這樣做的確省了不少事,但是這樣做當轉化為Excel文件時效果就不是很相同了。

    我們理想中的效果:

    

    但實際上會展示為:

    

    轉化為Excel文件時並未在固定的列數設置背景顏色,而是整行都被設置為黃色。針對其他的細節我們可以慢慢的去嘗試,去調整。

    此時我們先要針對現有的table標簽進行數據填充:

 1             ber.Append("<table border=\"1\">");
 2             ber.Append("<thead>");
 3             ber.Append("<tr><th  style=\"background-color:yellow\" colspan=\"7\" align=\"center\">物料匯總單</th></tr>");
 4 
 5             ber.Append("<tr>");
 6 
 7             ber.Append("<th style=\"background-color:yellow\">物料碼</th>");
 8             ber.Append("<th style=\"background-color:yellow\">物料名稱</th>");
 9             ber.Append("<th style=\"background-color:yellow\">型號</th>");
10             ber.Append("<th style=\"background-color:yellow\">單位</th>");
11             ber.Append("<th style=\"background-color:yellow\">數量</th>");
12             ber.Append("<th style=\"background-color:yellow\">備注</th>");
13             ber.Append("<th style=\"background-color:yellow\">排序</th>");
14 
15             ber.Append("</tr>");
16             ber.Append("</thead>");
17 
18             ber.Append("<tbody>");
19             foreach (ExcelTMaterial item in all_models)
20             {
21                 ber.Append("<tr>");
22                 ber.AppendFormat("<th>{0}</th>", item.mt_code);
23                 ber.AppendFormat("<th>{0}</th>", item.mt_name);
24                 ber.AppendFormat("<th>{0}</th>", item.mt_model);
25                 ber.AppendFormat("<th>{0}</th>", item.mt_unit);
26                 ber.AppendFormat("<th>{0}</th>", item.count);
27                 ber.AppendFormat("<th>{0}</th>", item.mt_remake);
28                 ber.AppendFormat("<th>{0}</th>", item.mt_sort);
29                 ber.Append("</tr>");
30             }
31 
32 
33             ber.Append("</tbody>");
34             ber.Append("</table>");     

      我們將數據填充完畢以后獲得到的將是字符串文本,然后我們則通過以下方法導出Excel文件

      1)通用輸出流方法

        /// <summary>
        /// 輸入HTTP頭,然后把指定的流輸出到指定的文件名,然后指定文件類型
        /// </summary>
        /// <param name="OutType">輸出類型</param>
        /// <param name="FileName">文件名稱</param>
        /// <param name="ExcelContent">內容</param>
        public void ExportToExcel(string OutType, string FileName, string dataSource)
        {
            lock (this)
            {
                System.Web.HttpContext.Current.Response.Charset = "UTF-8";
                System.Web.HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
                System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(FileName, System.Text.Encoding.UTF8).ToString());
                System.Web.HttpContext.Current.Response.ContentType = OutType;
                System.IO.StringWriter tw = new System.IO.StringWriter();
                System.Web.HttpContext.Current.Response.Output.Write(dataSource);
                System.Web.HttpContext.Current.Response.Flush();
                System.Web.HttpContext.Current.Response.End();
            }
        }

      2)調用方法獲取Excel文件下載

1             string data =GetMySourceStr();
2             ExportToExcel("application/ms-excel", "導出Excel文件.xls", data);    

        這里要注意參數:

         string OutType:application/ms-excel輸出方式;

        string FileName:指定文件的名稱+.xls,后綴我們最好不要更改,默認.xls即可;

        string dataSource:拼接好的數據源字符串;

       此時整體下來我們便可以完成簡單的Excel表格導出功能了。

       注:在某種特殊情況下,文檔數據會存在丟失現象,如:文件傳送給他人計算機,為避免這種情況只能采取導出后將內容Copy到新建的Excel文件中,因此此方法不推薦使用!(2019-01-28注)

 

 

    2、第三方插件進行Excel導出

      網上推薦使用:NPOI導出。以下是百度百科的介紹:

        NPOI是指構建在POI 3.x版本之上的一個程序,NPOI可以在沒有安裝Office的情況下對Word或Excel文檔進行讀寫操作。
        POI是一個開源的Java讀寫Excel、WORD等微軟OLE2組件文檔的項目。

      可以看出NPOI的優勢在於獨立性,不依賴於Office去完成一系列操作,針對Java和C#都可以使用;其官方網址:NPOI官方網站,由於暫時還未采用第三方插件進行導出,暫不對此進行介紹。而對於B\S端我個人更推薦使用此方法,因為它的一些基本操作以及相關的依賴,NPOI對於格式和生成的速度都是有一定優勢的。

    (2019-01-28新增)

     去年中旬開始,針對業務調整,發現微軟提供的microsoft.office.interop.excel.dll使用上雖然很方便,但是對於部署上真是一言難盡,比如之前的服務器賬號注銷、速度等問題,因此后續調整便采用NPOI。

      對於NPOI的使用十分的簡單且方便

     1)我們需要安裝或引用NPOI依賴包

      

     2)創建Book、Sheet、Row、Cell,NPOI在創建這些對象上很直觀明了,操作起來和寫文章一樣

類及接口 說明
NPOI.HSSF.UserModel.HSSFWorkbook 創建Excek文件對象
NPOI.SS.UserModel.ISheet Excel中的工作簿
NPOI.SS.UserModel.IRow Excel工作部中的行
NPOI.SS.UserModel.ICell Excel工作部中的單元格

       對於創建Excel文件及簡單填充數據很簡單(簡單的測試方法,Copy即可使用):

       

        public void G()
        {
            //創建Excel文件的對象
            HSSFWorkbook book = new HSSFWorkbook();
            //添加一個sheet
            ISheet sheet = book.CreateSheet($"工作簿1");

            //行下標記錄
            int rowIndex = 0;
            //創建首行
            IRow row0 = sheet.CreateRow(rowIndex++);
            //創建單元格
            ICell cell0 = row0.CreateCell(0);
            //設置單元格內容
            cell0.SetCellValue("測試首行");

            //創建多行
            for (int i = 0; i < 10; i++)
            {
                var row = sheet.CreateRow(rowIndex++);

                //連寫創建單元格並設置單元格內容 (一般這樣寫更好點)
                row.CreateCell(0).SetCellValue("A"+i.ToString());
            }
            
           using (FileStream st = new FileStream(AppDomain.CurrentDomain.BaseDirectory+ "test.xls", FileMode.OpenOrCreate))
            {
                book.Write(st);
            }
        }

     打開生成的文件如下圖:

    2)多工作簿實現

      我們只需要簡單改一改就可以實現,Book是固定唯一的,此時我們針對Sheet動態實現即可,一般可能是手動去創建,我們使用簡單循環實現一下吧

      

        public void G()
        {
            //創建Excel文件的對象
            HSSFWorkbook book = new HSSFWorkbook();
            //添加一個sheet
            for (int index = 0; index < 3; index++)
            {
                ISheet sheet = book.CreateSheet($"工作簿{(index + 1)}");

                //行下標記錄
                int rowIndex = 0;
                //創建首行
                IRow row0 = sheet.CreateRow(rowIndex++);
                //創建單元格
                ICell cell0 = row0.CreateCell(0);
                //設置單元格內容
                cell0.SetCellValue("測試首行");

                //創建多行
                for (int i = 0; i < 10; i++)
                {
                    var row = sheet.CreateRow(rowIndex++);

                    //連寫創建單元格並設置單元格內容 (一般這樣寫更好點)
                    row.CreateCell(0).SetCellValue("A" + i.ToString());
                }
            }
            
           using (FileStream st = new FileStream(AppDomain.CurrentDomain.BaseDirectory+ "test.xls", FileMode.OpenOrCreate))
            {
                book.Write(st);
            }
        }

      

    從以上可以看出,NPOI對於Excel導出很是實用,對於NPOI其他功能暫時還沒使用到,因此不做評價。

     注:因為工作中開始使用Java做服務,而Java提供了更為的Excel、Word、Pdf等文件的處理,因此后續考慮吧文件處理交給java服務程序去完成,.Net做核心功能業務。

 

 

 

     3、微軟提供的microsoft.office.interop.excel.dll

    microsoft.office.interop.excel.dll是針對COM+的包裝,它便於在托管代碼中使用,依賴本地安裝的Office軟件。如果本地未安裝Office則此方法不適合操作Excel以及其他相關如:

 

    這些都是微軟其Office產品提供的插件,唯一的缺點則是依賴性,我們在本地開發需要安裝Office,部署在服務器也是需要安裝Office,在B\S端的響應速度不是太好。

    1)DLL引用

      Microsoft.Office.Interop.Excel.dll、Microsoft.Office.core.dll

    2)引用方式

      Microsoft.Office.Interop.Excel.dll:

      

 

      通過NuGet包管理器進行安裝,要與本地Office版本相對應。

      Microsoft.Office.core.dll:

      

 

      通過項目的右鍵>添加引用>COM>類型庫 --查找-->Microsoft Office 15.0 Object Library(此處針對Office2013,其它版本可以查找相應的Microsoft Office xx.0 Object Library)。

      3)使用方法

      a.引入命名空間

        我們可以直接引入一下命名空間:

             using Microsoft.Office.Interop.Excel;

 

         也可以這樣引入:

              using OfcExcel = Microsoft.Office.Interop.Excel;

 

         這樣做主要是針對較長方法的簡寫。

      b.方法的實現

      

 

      我們首先創建一個ApplicationClass對象,但是發現似乎提示了一個錯誤,第一次使用的時候發現代碼並沒用什么問題,后來查閱了一些文檔和教程我們只需要做一下操作便可以解決:

        在引用中找到Microsoft.Office.Interop.Excel查看屬性->嵌入互操作類型由True改為False即可。

      

      再編寫以下代碼:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using Microsoft.Office.Interop.Excel;
 7 using System.Drawing;
 8 using System.IO;
 9 
10 namespace OutExcel
11 {
12     public class Utility
13     {
14         public static void ExcelOut()
15         {
16 
17             ApplicationClass app = new ApplicationClass();
18 
19             /*針對Excel 對象及工作簿單元格操作*/
20             Workbook workbook_1 = (Workbook)app.Workbooks.Add(true);//添加workbook
21             Worksheet worksheet_1 = (Worksheet)workbook_1.Worksheets[1];//選擇第一個,即默認的工作簿
22             Range sheet_cells = worksheet_1.Cells;//工作簿單元格
23 
24             string[] columns = new string[] { "系統", "設備信息", "類別", "代碼", "名稱", "型號", "單位", "數量", "備注" };//列數
25             int row = 1;//默認行數
26             Range rg = sheet_cells.Range[app.Cells[row, 1], app.Cells[row, columns.Length]];//選擇光標-----選擇第一行 1 到10列
27             rg.Merge(false);//合並單元格
28             rg.Value2 = "內容";//設置選中單元格內容
29             row++;//下移一行
30          
31           
32             for (int index = 0; index < columns.Length; index++)
33             {
34                 sheet_cells[row, index + 1] = columns[index];//設置列標題內容
35             }
36 
37             rg = sheet_cells.Range[app.Cells[1, 1], app.Cells[row, columns.Length]];//選擇標題頭
38             
39             /*針對選中單元格樣式設置*/
40             rg.Borders.LineStyle = XlLineStyle.xlContinuous;
41             rg.HorizontalAlignment = XlHAlign.xlHAlignCenter;
42             rg.VerticalAlignment = XlHAlign.xlHAlignCenter;
43             rg.Interior.Color = Color.Yellow;
44 
45             string path_ = AppDomain.CurrentDomain.BaseDirectory.ToString()+ "excel導出.xlsx";
46             if (File.Exists(path_))
47             {
48                 File.Delete(path_);
49             }
50             try
51             {
52                 workbook_1.SaveAs(path_, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing
, XlSaveAsAccessMode.xlNoChange, 1, false, Type.Missing, Type.Missing, Type.Missing); 53 54 } 55 catch (Exception ex) 56 { 57 path_ = null; 58 } 59 finally 60 { 61 workbook_1.Close(true, path_, Type.Missing); 62 workbook_1 = null; 63 } 64 } 65 } 66 }

 

       以上代碼只是參考示例基礎操作,你可以使用過程中對常用方法進行封裝。

      C\S端再調用此方法時會在Debug目錄下生成:

      

        B\S生成則在根目錄下,我們可以指定自己存放的路徑。

      生成結果:

        

       此時針對Microsoft.Office.Interop.Excel.dll操作基本完成,而針對它的操作方法可以查閱相關文檔即可實現。對於B\S調用出現的問題可以參考下面的方法解決。

二、提示的錯誤信息

  1、導出Excel提示信息錯誤

檢索 COM 類工廠中 CLSID 為 {00024500-0000-0000-C000-000000000046} 的組件失敗,原因是出現以下錯誤: 8000401a 因為配置標識不正確,系統無法開始服務器進程。請檢查用戶名和密碼。 (異常來自 HRESULT:0x8000401A)。

 

  1)問題表現

    服務器斷開連接,導出功能報錯即以上錯誤。服務器登陸,導出正常。

  2)分析

    賬號的登陸與斷開,表現為賬戶所屬權限問題。

  3)解決過程

    參照着網上的一些教程總結,得出一下方法:

      a.設置DCOM

        win+r鍵,輸入:dcomcnfg.exe 調出=》組件服務

        選擇 組件服務>計算機>我的電腦>DCOM 配置 --查找-->Microsoft Excel Application

        右鍵>屬性>安全,設置如下

        標識設置:

        如果此時還是報錯,則可以考慮設置 標識 下列用戶 即指定一個用戶:

         保存配置在關閉,斷開服務器連接,導出Excel不在報8000401A錯誤。

    問題0x8000401A 參考文獻:http://blog.csdn.net/caobingyi/article/details/5175281

 

 

 

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM