1. 程式人生 > >C# 匯出excel並設定格式

C# 匯出excel並設定格式

一.生成Exel的方法

生成Excel的方法為呼叫本地Office COM元件,操作Excel。新建專案後,新增對應Office版本的Microsoft.Office.Interop.Excel的引用,如圖1-1所示。

1-1 新增Microsoft.Office.Interop.Excel引用

為方便起見,這裡以一個示例程式說明我的過程。示例程式整體結構如程式碼清單1-1所示。

程式碼清單1-1 示例程式結構

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Excel=Microsoft.Office.Interop.Excel;

namespace excel

{

class Program

{

private Excel.Application app = null;

private Excel.Workbook workbook = null;

private Excel.Worksheet worksheet = null;

private Excel.Range workSheet_range = null;

static void Main(string[] args)

{

}

public void createExcel()

{

}

public void addData(int row, int col, string data, string formatstring cell1string cell2)

{

}

public void export()

{

}

}

}

首先我先聲明瞭四個欄位,分別解釋如下:

1)Excel.Application app。Application物件表示Excel應用程式本身。Application物件公開了大量有關正在執行的應用程式、應用於該例項的選項以及在該例項中開啟的當前使用者的物件的資訊。

2)Excel.Workbook workbook。Excel.Workbook類表示Excel應用程式中的單個工作簿。

3)Excel.Worksheet worksheet。Excel提供Sheets集合作為 Microsoft.Office.Interop.Excel.Workbook 物件的屬性,但是Excel中沒有Sheet類。相反,Sheets 集合的每個成員都是一個Microsoft.Office.Interop.Excel.Worksheet物件,或者是一個 Microsoft.Office.Interop.Excel.Chart物件。

4)Excel.Range workSheet_range。Excel.Range物件是Excel應用程式中最常用的物件。在能夠處理Excel內的任何範圍之前,必須將它表示為Range物件,並處理該物件的方法和屬性。Range物件表示一個單元格、一行、一列、包含一個或多個單元格塊(可以連續,也可以不連續)的單元格選定範圍,甚至多個工作表中的一組單元格。

createExcel()方法用來建立Excel例項,也就是初始化宣告的四個變數,實現程式碼如程式碼清單1-2所示。

程式碼清單1-2 初始化變數

public void createExcel()

{

app = new Excel.Application();

app.Visible = true;

workbook = app.Workbooks.Add(1);//建立workbook

worksheet = (Excel.Worksheet)workbook.Sheets[1];//建立worksheet

}

如程式碼清單1-2,Workbook物件由Application物件建立,Worksheet物件由Workbook物件建立。

addData()方法用來向表格中新增資料,四個引數分別為行、列、資料、資料格式,範圍起始格、範圍結束格。實現程式碼如程式碼清單1-3所示。

程式碼清單1-3 新增資料

worksheet.Cells[row, col] = data;

workSheet_range = worksheet.get_Range(cell1, cell2);

workSheet_range.Borders.Color = System.Drawing.Color.Black.ToArgb();

workSheet_range.NumberFormat = format;

Excel中的每一個格以行和列組成的座標來唯一標識,這裡行標識是數字,從1到n;列標識是字母,從A到Z,從AA到AZ……。

workSheet_range物件由worksheet.get_Range(cell1, cell2)方法來初始化,從cell1到cell2會被作為一個整體處理。workSheet_range.NumberFormat設定該區域內的字元格式化方式。

export()方法用來匯出生成的Excel,實現如程式碼清單1-4所示。

程式碼清單1-4 匯出Excel

public void export()

{

workbook.SaveCopyAs(@"D:/aa.xls");

app.Quit();

}

Workbook物件由三個方法用來儲存Excel檔案,分別為Save方法、SaveCopyAs方法和SaveAs方法,這裡使用SaveCopyAs方法。儲存之好呼叫Application物件的Quit()方法釋放資源。

在本地測試一切正常,測試結果如圖1-2所示。

1-2 測試結果

二.合併單元格與數字列標識轉字母列標識

合併單元格的時候,必須要傳遞以字母表示的列標識給Excel.Range物件的.Mergeint)方法,但是我們取資料和填充資料使用的都是數字標識,這時候必須轉成如圖1-3的形式。

1-3 Excel的字母列標識

程式碼清單1-5提供的演算法可解決這個問題。

程式碼清單1-5 數字列標識轉字母列標識

public string ToName(int index)

{

if (index <= 0)

throw new Exception("invaild parameter");

index--;

List<string> chars = new List<string>();

do

{

if (chars.Count > 0)

index--;

chars.Insert(0, ((char)(index % 26 + (int)'A' )).ToString());

index = (int)((index - index % 26) / 26);

} while (index > 0);

return String.Join(string.Empty, chars.ToArray());

}

三. "異常來自 HRESULT:0x800A03EC "的原因

一不小心就會出"異常來自 HRESULT:0x800A03EC "的異常,原因很簡單,Excel的行列都是從1開始的,如果我們習慣性的給worksheet.Cells[0, 0]或者worksheet.Cells[1, 0]或者worksheet.Cells[0, 1]賦值,就會引發該異常。

四. "未將物件引用設定到物件例項"和伺服器端部署

客戶端一切執行正常,接下來就是要把DLL部署到伺服器上。可是伺服器根本沒用安裝Office,在網站找了很久,也沒找到此種方法的解決方案。無奈就安裝了Office,本來以為萬事大吉,但是每次都提示"未將物件引用設定到物件例項"。採用拋異常的方法才知道示例程式中的幾個主要欄位都為空,那就是本地的COM根本沒呼叫成功。找到http://www.cnblogs.com/Mainz/archive/2009/11/11/microsoft_office_interop_excel.html文章,於是乎又進行了如下操作。

從伺服器上把EXCEL.EXE拷到了本機上,然後從VS2010的命令列啟動TlbImp,執行命令:TlbImp /out:Interop.Excel.dll Excel.exe。生成Interop.Excel.dll

在專案中去除了Microsoft.Office.Interop.Excel.dll的引用,新增Interop.Excel.dll,將頂部的using Excel=Microsoft.Office.Interop.Excel,該為using Excel= Interop.Excel,本地執行程式沒有問題。再次更新伺服器端程式,結果又出了新的異常:檢索 COM 類工廠中 CLSID 為 {00024500-0000-0000-C000-000000000046} 的元件時失敗,原因是出現以下錯誤: 80080005

五. "80080005異常"與許可權配置

"80080005異常"是應用程式對COM元件操作許可權不足引起的。於是有了下面的操作:

1)控制面板->管理工具->元件服務->計算機->我的電腦->DCOM-> Microsoft Excel 應用程式

2)單擊屬性開啟此應用程式的屬性對話方塊。

3) 單擊標識選項卡,然後選擇互動式使用者。

4) 單擊預設安全性選項卡。設定當前伺服器與ASP.NET相關的使用者的訪問許可權。

5)單擊啟動許可權的編輯預設值。設定ASP.NET相關的使用者的訪問許可權。

至此,程式才執行成功,可謂一波三折。

六.關閉Excel程序

如果使用這種方式使用者每匯出一個Excel檔案,伺服器端就會啟動一個Excel程序。這回引起兩個問題,一是耗費伺服器資源,二是當程序數達到上限時,會引發異常,呼叫COM失敗。這個時候要想辦法結束Excel程序。我採用了殺程序的方式,類似下面的做法:

private void DoExcel()
{
Microsoft.Office.Interop.Excel.Application application = new Microsoft.Office.Interop.Excel.Application();
//這裡釋放所有引用的資源
application.Quit();
KillExcel(application);
}

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd,out int ID);
public static void KillExcel(Microsoft.Office.Interop.Excel.Application excel)
{
IntPtr t = new IntPtr(excel.Hwnd); //得到這個控制代碼,具體作用是得到這塊記憶體入口

int k = 0;
GetWindowThreadProcessId(t, out k); //得到本程序唯一標誌k
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); //得到對程序k的引用
p.Kill(); //關閉程序k
}