C# 操作 Excel 常見問題收集和整理(定期更新,歡迎交流)


經常會有項目需要把表格導出為 Excel 文件,或者是導入一份 Excel 來操作,那么如何在 C# 中操作 Excel 文件成了一個最基本的問題。

做開發這幾年來,陸陸續續也接觸過這樣的需求,但因為不頻繁,所以經常是遇到問題再去網上搜。最近的一個項目,要導出的這個 Excel 涉及了很多比較偏僻的操作,所以決定在這里開一篇文章,專門用來收集和整理使用到的代碼,以及一些技巧。如果各位看官有一些自己的心得,或者有更好的方案,也歡迎交流。我會時不時更新一下。

 

0. 使用之前

在寫代碼之前,我們需要先添加引用,在 程序集擴展 里面:Microsoft.Office.Interop.Excel
還有要注意的是,引用之后,需要將屬性中的「嵌入互操作類型」設置為 Flase,不然編譯時可能會出錯。
然后就是記得 using 啦:

using Microsoft.Office.Interop.Excel;
using System.Reflection;

▲ 這里的第二個 using 是因為在 Excel 操作中會經常用到一個 Missing.Value 的默認值,所以需要先引用 System.Reflection。

 

1. 開始使用

一般在使用中,我們只是操作一份 Excel 中的第一個工作表(sheet),下面來最簡單的創建和讀取一份 Excel 中的第一個 sheet。

// 定義一個 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,這和大多數程序語法有區別。

 

2. 使用之后

既然已經把 Excel 都創建出來了,我們就先來說說使用之后的結束,以及保存文件,需要注意的問題。這就好比在寫代碼,兩個花括號都是同時敲的,過后再來寫里面的代碼。

許多資料中,Excel 使用之后都直接就 excel = null; 來結束代碼,這些朋友難道沒發現,這樣會在系統中留下許多 EXCEL.EXE 的進程嗎?如下圖:

如果這是在用戶的客戶端,可能會因為關機,而把這個問題忽略。但如果是在服務器上生成 Excel 文件,一個用戶生成一次,就產生一個進程,那么后果可想而知。所以我們要來先說說使用之后怎么結束 Excel 的進程。
結束 Excel 不能單單把 EXCEL.EXE 結束就好,這樣的話,如果用戶正好打開了一個 Excel 也會被結束掉。
下面是正確結束 Excel 的代碼:

[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

接下來就是比較保險的關閉,以及調用上面的代碼:

// 關閉電子表格,釋放資源
wb.Close();
wb = null;

// 退出 Excel,釋放資源
excel.Quit();
KillExcel(excel);
excel = null;

 

3. 保存時的格式問題

文件格式和擴展名不匹配。文件可能已損壞或不安全。」看起來似乎很嚴重,尤其對一些電腦小白來說,不安全這個詞很耀眼。這個問題,可能很多朋友在做 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 文件,會發現直接就打開了,不會再出現上面的問題了。

 

4. 常用的格式設置

在操作 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 的速度會有點慢。

 

5. 常用的打印設置

這部分可能在網上比較少見,但一些項目中也會有相關的需求,比如要默認橫向紙張啦,打印標題行啦(就是不管打印到第幾頁,都會出現這一行,一般是表格第一行)等等,我們來看看代碼吧:

// 設置橫向紙張
ws.PageSetup.Orientation = XlPageOrientation.xlLandscape;

// 設置打印標題的范圍
ws.PageSetup.PrintTitleRows = "$3:$3";

 

6. 其它設置

還有一些其它的設置和操作,暫時先都整理在這吧。

// 設置電子表格的名稱
ws.Name = "Hello C#";

 

7. 關於生成速度慢的解決方案…

上面我們有提到,使用程序來生成 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,不然在保存的時候,會提示兼容問題!

 

最后

准備寫這篇文章,已經計划了好幾天,一直到昨晚才動筆,花了兩個晚上,大部分代碼在寫文章的時候,還重新在 Visual Studio 中實踐了一次,花了兩個晚上寫完。除了方便自己以后用,也希望能幫到有需求的朋友。
如果你也有這方面的經驗,或者技巧,或者覺得文章中有什么問題,非常歡迎一起交流!


免責聲明!

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



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