常常會有項目須要把表格導出爲 Excel 文件,或者是導入一份 Excel 來操做,那麼如何在 C# 中操做 Excel 文件成了一個最基本的問題。安全
作開發這幾年來,陸陸續續也接觸過這樣的需求,但由於不頻繁,因此常常是遇到問題再去網上搜。最近的一個項目,要導出的這個 Excel 涉及了不少比較偏僻的操做,因此決定在這裏開一篇文章,專門用來收集和整理使用到的代碼,以及一些技巧。若是各位看官有一些本身的心得,或者有更好的方案,也歡迎交流。我會時不時更新一下。服務器
在寫代碼以前,咱們須要先添加引用,在 程序集 – 擴展 裏面:Microsoft.Office.Interop.Excel。
還有要注意的是,引用以後,須要將屬性中的「嵌入互操做類型」設置爲 Flase,否則編譯時可能會出錯。
而後就是記得 using 啦:字體
using Microsoft.Office.Interop.Excel; using System.Reflection;
▲ 這裏的第二個 using 是由於在 Excel 操做中會常常用到一個 Missing.Value 的默認值,因此須要先引用 System.Reflection。ui
通常在使用中,咱們只是操做一份 Excel 中的第一個工做表(sheet),下面來最簡單的建立和讀取一份 Excel 中的第一個 sheet。this
// 定義一個 Missing 的值,方便後面使用 Missing miss = Missing.Value; // 建立 Excel,並制定是不可見的 ApplicationClass excel = new ApplicationClass(); excel.Visible = false; // 新建一份電子表格,或者打開現有的文件 Workbook wb = excel.Workbooks.Add(); Workbook wb = excel.Workbooks.Open("demo.xls"); // 取獲得第一個工做表,或者取得當前默認的工做表 Worksheet ws = wb.Sheets[1] as Worksheet; Worksheet ws = wb.ActiveSheet as Worksheet;
▲ 注意,在 Excel 的操做中,許多時候,索引是從 1 開始的,而不是 0,這和大多數程序語法有區別。編碼
既然已經把 Excel 都建立出來了,咱們就先來講說使用以後的結束,以及保存文件,須要注意的問題。這就比如在寫代碼,兩個花括號都是同時敲的,事後再來寫裏面的代碼。spa
許多資料中,Excel 使用以後都直接就 excel = null; 來結束代碼,這些朋友難道沒發現,這樣會在系統中留下許多 EXCEL.EXE 的進程嗎?以下圖:excel
若是這是在用戶的客戶端,可能會由於關機,而把這個問題忽略。但若是是在服務器上生成 Excel 文件,一個用戶生成一次,就產生一個進程,那麼後果可想而知。因此咱們要來先說說使用以後怎麼結束 Excel 的進程。
結束 Excel 不能單單把 EXCEL.EXE 結束就好,這樣的話,若是用戶正好打開了一個 Excel 也會被結束掉。
下面是正確結束 Excel 的代碼:code
[DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID); // 結束 Excel 進程 public static void KillExcel(Application excel) { IntPtr t = new IntPtr(excel.Hwnd); int k = 0; GetWindowThreadProcessId(t, out k); System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k); p.Kill(); }
▲ 注意 DllImport 須要 using System.Runtime.InteropServices 。orm
接下來就是比較保險的關閉,以及調用上面的代碼:
// 關閉電子表格,釋放資源 wb.Close(); wb = null; // 退出 Excel,釋放資源 excel.Quit(); KillExcel(excel); excel = null;
「文件格式和擴展名不匹配。文件可能已損壞或不安全。」看起來彷佛很嚴重,尤爲對一些電腦小白來講,不安全這個詞很耀眼。這個問題,可能不少朋友在作 Excel 導出的時候,都會遇到,包括我本身使用一些軟件也遇過,絕大多數都沒有對這個問題進行處理,以爲讓用戶點一下「是」就行了。但對於我這種相對注重用戶體驗的開發者來講,這樣固然是不行的。那麼究竟是什麼形成的?
其實解決這個問題很是簡單,之因此會出現這個問題,是和 Office Excel 的版本有關係。咱們都知道 Excel 有一個 97-2003 的格式,就是最多見的 .xls 文件,除了這個還有一種 .xlsx 文件,這種是自 Office Excel 2007 以後有的新格式,除了這些,Excel 還支持把表格保存爲 .xml 甚至是純文本的格式。而咱們用程序在生成 Excel 的時候,考慮到國內還有一大批 Office 2003 的使用者,因此咱們都會保存爲 .xls 以便更好的兼容他們。大部分都是像下面的代碼這個保存的:
// 保存 wb.SaveAs("demo.xls");
雖然你的保存路徑中有包含 .xls 後綴名,但其實這個時候,Excel 並不知道你是要以什麼格式去保存,因此它多是無格式的,或者是當前系統中 Office 版本的默認格式。
如今咱們來看看 SaveAs 的參數中,會發現還有第二個參數 FileFormat,顧名思義,就是文件格式,正好是咱們要的參數,因此咱們只要告訴 Excel 要保存的格式,問題迎面而解:
// 保存,格式編碼爲56(xls)(.xlsx 的編碼爲51) wb.SaveAs("demo.xls", 56);
如今再打開生成的 demo.xls 文件,會發現直接就打開了,不會再出現上面的問題了。
在操做 Excel 的時候,除了上面這些基礎問題,還有就是一些常見的格式設置。包括字體字號、粗體、合併單元格、垂直居中、橫向居中、行高、列寬、單元格格式,邊框樣式,等等。下面的代碼就包含了這些經常使用的設置:
// 選擇一塊區域(一個或多個單元格之間) Range range = ws.get_Range(ws.Cells[1, 1], ws.Cells[2, 10]); // 設定單元格格式,@是指文本格式(導出一串長數字時,例如手機號碼,會被處理爲數字,因此咱們要強制爲文本) range.NumberFormat = "@"; // 合併單元格 range.MergeCells = true; // 設置行高、列寬 range.RowHeight = 35; range.ColumnWidth = 100; // 設置字體字號、粗體、字體(還有大多數字體相關的都在 Font 屬性中) range.Font.Size = 12; range.Font.Bold = true; range.Font.Name = "楷體"; // 橫向居中、垂直居中 range.HorizontalAlignment = XlHAlign.xlHAlignCenter; range.VerticalAlignment = XlHAlign.xlHAlignCenter; // 設置邊框 range.Borders.LineStyle = 1; range.Borders.LineStyle = XlLineStyle.xlContinuous; // 給單元格設置值(內容) range.set_Value(miss, "abel.cnblogs.com");
比較麻煩的是,每操做一個區域,咱們就要從新設定一次 Range,這至關於在 Excel 實際作了一次選擇某些單元格的操做,因此數據量大的話,生成 Excel 的速度會有點慢。
這部分可能在網上比較少見,但一些項目中也會有相關的需求,好比要默認橫向紙張啦,打印標題行啦(就是無論打印到第幾頁,都會出現這一行,通常是表格第一行)等等,咱們來看看代碼吧:
// 設置橫向紙張 ws.PageSetup.Orientation = XlPageOrientation.xlLandscape; // 設置打印標題的範圍 ws.PageSetup.PrintTitleRows = "$3:$3";
還有一些其它的設置和操做,暫時先都整理在這吧。
// 設置電子表格的名稱 ws.Name = "Hello C#";
上面咱們有提到,使用程序來生成 Excel,遇到數據量大的話(十萬級的數據就足夠了),會比較慢的問題,這個怎麼破?
其實咱們能夠不使用 Excel 操做類來生成,而是直接用 IO 來生成 xml 格式的 Excel 表格,最後保存爲 .xls 文件便可,速度能夠提升N倍。固然,會出現上面第三點說的問題。
那有沒有速度又快,又不會出現那個安全提示的方法呢?也是有的,來看看代碼:
// 打開 XML 格式的 Excel 文件 Workbook wb = excel.Workbooks.OpenXML("temp.xml"); // 再保存爲真正 xls 格式的 Excel 文件 wb.SaveAs("demo.xls", 56);
是的,方法就是先打開一份用 IO 生成好的 xml 格式的 Excel,再另存爲 Office 97-2003 格式的 xls 文件。 注意,這個方法只適合格式簡單的 Excel,否則在保存的時候,會提示兼容問題!