[C# 開發技巧系列]使用C#操作Word和Excel程式

weixin_34127717發表於2017-11-10

一、引言

  在我們日常辦公中,我們經常可能遇到一些重複性的工作的,比如,我們在寫畢業設計的時候,有時候我們寫的過程中不注意,當整篇畢業論文寫完之後,發現在畢業論文中存在很多空白的段落,這是我們就需要人工重新審閱一遍論文,再手動刪除一些空白行,由於畢業論文也不是一篇,有開題報告啊,文獻翻譯等等,這樣就可能需要我們人工都去審閱一篇把一些空白行刪除,這樣既花時間,我們也看的累。然後還有一個例子就是——我們人事部門的MM們,一到月末的時候就需要給本月的壽星員工傳送郵件來通知參加生日會,如果員工資訊是在Excel中的話,這時候人事的MM就要手動地從中查詢本月壽星的郵箱,然後用Outlook一個一個新增郵件地址來給本月壽星傳送郵件的,為了讓人事MM們不再那麼累,所以就想能不能用程式自動化地完成這一系列的過程呢?答案是肯定的,下面就讓我來實現上面的兩個需求的,使我們(尤其是人事MM們)的辦公更加Easy。


二、自動刪除Word中的空白行和頁

  在引言部分,我們已經提出了這個需求的。記得當時在寫畢業論文的時候,我也做過這些重複的事情,經常寫完之後會再去審閱一遍畢業論文中的所有文件,然後手動把一些空白行刪除掉,由於當時並不知道可以對Word來進行自動化程式設計,所以只能傻傻地做這樣一些重複的事情。但是現在不一樣了,自從接觸了VSTO之後,才知道Office一系列產品都是提供了一些公開的API的,我們可以利用這些物件使我們自定義Office程式和使Office自動化地工作,下面就具體講講如何實現這個小的工具的。

首先,我們先明確下這個工具需要實現的功能——自動移除Word文件中的空白行。然後向大家解釋下實現該工具的思路:

  • 我們開啟一個Word文件,該Word文件就是一個Word.Document物件

  • Word文件中內容都是段落組成的,然而段落在Word物件模型中是Word.Paragraph物件

  • 空白行或空白頁也就是段落的內容為空,明白了這點,我們就可以在程式中對段落物件的文字進行判斷,如果段落內容為空,我們就刪除該段落,這樣也就實現了移除空白行的功能了。

  有了上面的思路之後,然後大家只需要瞭解Word中物件模型,然後通過物件模型找到段落物件,然後再判斷它的文字是否為空,為空就刪除段落,不為空就什麼都不做。所以思路有了之後,就是要了解Word物件模型了,對於這部分內容,大家可以參考我部落格的中的——建立Word解決方案。由於程式碼中都有註釋,這裡就直接看實現該工具的核心程式碼:


  1. string[] wordPatharray = null;

  2. // 開啟需要操作的Word文件

  3. privatevoid btnOpen_Click(object sender, EventArgs e)

  4.        {

  5. using (OpenFileDialog openFileDialog = new OpenFileDialog())

  6.            {

  7.                openFileDialog.Filter = "Word document(*.doc;*.docx)|*.dox;**.docx|All Files(*.*)|*.*";

  8. // 設定允許選擇多個檔案,該屬性預設為false的,即只允許選擇一個檔案

  9.                openFileDialog.Multiselect = true;

  10. if (openFileDialog.ShowDialog() == DialogResult.OK)

  11.                {

  12.                    txtWordPath.Text = openFileDialog.FileName;

  13. // 獲得所有選定檔案的檔名

  14.                    wordPatharray = openFileDialog.FileNames;

  15.                }

  16.            }

  17.        }

  18. // 移除Word中的所有空頁

  19. privatevoid btnRemove_Click(object sender, EventArgs e)

  20.        {

  21.            Word.Application wordapp = null;

  22.            Word.Document doc = null;

  23. try

  24.            {

  25. // 啟動Word應用程式並設定不可見

  26.                wordapp = new Word.Application();

  27. // 如果不設定該屬性,就可以看到Word程式的啟動過程,這個和我們手動啟動Word是一樣的

  28.                wordapp.Visible = false;

  29. // 遍歷每個檔名

  30. foreach (var wordpath in wordPatharray)

  31.                {

  32.                    doc = wordapp.Documents.Open(wordpath);

  33. // 刪除所有空白頁面

  34.                    Word.Paragraph paragraph;

  35.                    Word.Paragraphs paragraphs = doc.Paragraphs;

  36. for (int i = paragraphs.Count; i > 0; i--)

  37.                    {

  38.                        paragraph = paragraphs[i];

  39. //  如果段落的文字為空的話,首先選擇該段落,然後再呼叫Word中Selection物件的Delete方法來刪除

  40. // 不為空什麼都不做

  41. if (paragraph.Range.Text.Trim() == string.Empty)

  42.                        {

  43.                            paragraph.Range.Select();

  44.                            wordapp.Selection.Delete();

  45.                        }

  46.                    }

  47. if (doc != null)

  48.                    {

  49. // 先儲存所有修改再關閉Word文件

  50.                        doc.Save();

  51.                        ((Word._Document)doc).Close();

  52.                    }

  53.                }

  54.                MessageBox.Show("刪除空白行成功");

  55.            }

  56. catch (Exception ex)

  57.            {

  58.                MessageBox.Show("異常發生,異常資訊為:" + ex.Message);

  59.            }

  60. finally

  61.            {

  62. // 釋放資源

  63. // 退出Word程式

  64. if (wordapp != null)

  65.                {

  66.                    ((Word._Application)wordapp).Quit();

  67.                }

  68.                doc = null;

  69.                wordapp = null;

  70.            }

  71.        }


為了測試該程式的正確性,這裡我建立了兩個測試文件,為了測試,我故意在文件中刪除了空白行和空白頁面,下面是兩個測試文件的截圖:

16162054-fa4b663c8e7f41fd91f82483f12dba6

下面就看看該工具的執行效果(效果圖是一段動畫,認為這樣可以更加說明執行效果)

16163616-e1879e1019b5404491554b1776d2ced


三、人事部門的福音——自動給本月壽星員工傳送郵件提醒

為了幫助大家更好地理解該程式,還是像之前一樣,首先說說實現該程式的思路:

  • 我們首先需要開啟員工資訊表,此時我們可以利用Excel物件模型中的Excel.Application.Workbooks.Open方法來獲得一個工作簿物件,關於更多Excel物件模型的內容可以轉向——建立Excel解決方案

  • 通過第一步我們已經獲得了工作簿物件了,然後通過遍歷工作簿中的啟用表,即表格一(Sheet1),我們可以通過workbook.ActiveSheet來獲得表格一物件。

  • 遍歷表格一中的所有行來找到生日資訊中的月份,如果月份等於當前月份,就給該員工的郵箱進行發郵件。

  • 對於自動傳送郵件的實現,該實現和我們手動操作Outlook過程是一樣,手動操作時,我們需要手動開啟Outlook(在程式中就是建立Outlook應用程式物件),然後點選新建郵件(在程式中就是通過Applicatin物件的CreateItem(Outlook.OlItemType.olMailItem)方法來建立一個郵件專案),在新建郵件視窗中指定收件人,主題,郵件內容之後,點選Outlook中的傳送郵件按鈕(在程式中就是通過指定 Outlook.MailItem物件(即代表一個郵件窗體)的To(收件人)、Subject(主題)、Body(郵件內容)屬性,然後再呼叫Send方法來傳送郵件)

明白了思路之後,我們理解程式碼會更加容易了,具體實現程式碼為:


  1. using System;

  2. using System.IO;

  3. using System.Runtime.InteropServices;

  4. using System.Windows.Forms;

  5. // 引用Excel和Outlook的名稱空間

  6. using Excel = Microsoft.Office.Interop.Excel;

  7. using Outlook = Microsoft.Office.Interop.Outlook;

  8. string excelpath = string.Empty;

  9. // 開啟員工表格

  10. privatevoid btnOpen_Click(object sender, EventArgs e)

  11.        {

  12. using (OpenFileDialog openFileDialog = new OpenFileDialog())

  13.            {

  14.                openFileDialog.Filter = "Excel File(*.xls;*.xlsx)|*.xls;**.xlsx|All Files(*.*)|*.*";

  15. if (openFileDialog.ShowDialog() == DialogResult.OK)

  16.                {

  17.                    txtExcelPath.Text = openFileDialog.FileName;

  18.                    excelpath = openFileDialog.FileName;

  19.                }

  20.            }

  21.        }

  22. // 自動給本月壽星發郵件通知

  23. privatevoid btnSendEmail_Click(object sender, EventArgs e)

  24.        {

  25. if (!File.Exists(txtExcelPath.Text))

  26.            {

  27.                MessageBox.Show("員工表路徑不存在,請確保輸入正確的檔案路徑");

  28. return;

  29.            }

  30. if (txbBirthday.Text.Trim() == string.Empty || txbEmail.Text.Trim() == string.Empty)

  31.            {

  32.                MessageBox.Show("請先輸入員工表中生日資訊所在的列和郵箱資訊所在的列!");

  33. return;

  34.            }

  35. // 輸入資訊都正確時開始傳送郵件

  36.            SendEmail(int.Parse(txbBirthday.Text.Trim()), int.Parse(txbEmail.Text.Trim()));

  37.        }

  38. // 傳送郵件方法

  39. privatevoid SendEmail(int birthDayColumn,int emailColumn)

  40.        {

  41. // 獲得當前月份

  42. int nowmonth = DateTime.Now.Month;

  43. // 傳送郵件地址字串

  44. string toEmailString = string.Empty;

  45. string emailBody="請收到郵件的員工,請本月28號到休閒室來參加生日Party";

  46.            Excel.Application excelApp = null;

  47.            Excel.Workbook workbook =null;

  48.            Excel.Worksheet worksheet = null;

  49.            Excel.Range range = null;

  50. try

  51.            {

  52. // 新建Excel應用程式被設定它不可見

  53.                excelApp = new Excel.Application();

  54.                excelApp.Visible = false;

  55.                workbook = excelApp.Workbooks.Open(excelpath);

  56. // 獲得開啟檔案的啟用表格

  57.               worksheet= workbook.ActiveSheet;

  58. // 遍歷表格中的所有行

  59. for (int row = 2; row < worksheet.UsedRange.Rows.Count + 1; row++)

  60.                {

  61. // 因為我的測試表格中第四列是生日資訊,在Excel中第一行的下標是從1開始的

  62. // 這裡本來需要在頁面設定一個文字框讓使用者填寫生日資訊是在那一列的

  63. // 這裡為了測試就直接在程式中指定

  64. // 下面的Range就代表生日列中每一個單元格

  65.                    range = worksheet.Cells[row, birthDayColumn];

  66. // 我們可以通過Range.Value來獲得單元格中的生日資訊

  67. // 因為我生日單元格中為日期格式,所以獲得的是日期型別,所以直接通過Month屬性來獲得月份

  68. int month = range.Value.Month;

  69. // 如果我們的Excel文件中生日時間設定為文字格式的話,這時候就需要通過分割字串的方式來獲得月份

  70. // 通過Split函式來把生日資訊以'/'符號分隔,分隔的陣列的第二個就是月份

  71. //int month = Int32.Parse(birthday.Split('/')[1]);

  72. // 如果月份等於當前月的話,就給這個人發郵件

  73. if (month == nowmonth)

  74.                    {

  75. // 獲得本月生日員工的郵件地址

  76.                        toEmailString += ";" + ((Excel.Range)worksheet.Cells[row, emailColumn]).Value;

  77.                    }

  78.                }

  79.            }

  80. catch (Exception ex)

  81.            {

  82.                MessageBox.Show("讀取員工表格時出錯,異常資訊為:" + ex.Message);

  83. return;

  84.            }

  85. finally

  86.            {

  87.                workbook.Close(Excel.XlSaveAction.xlDoNotSaveChanges);

  88.                excelApp.Quit();

  89. if (workbook != null)

  90.                {

  91.                    Marshal.FinalReleaseComObject(workbook);

  92.                    workbook = null;

  93.                }

  94. if (excelApp != null)

  95.                {

  96.                    Marshal.FinalReleaseComObject(excelApp);

  97.                    excelApp = null;

  98.                }

  99.            }

  100. if (CreateEmailItem("生日提醒", toEmailString, emailBody))

  101.            {

  102.                MessageBox.Show("成功給本月壽星傳送郵件提醒");

  103.            }

  104.        }

  105. // 建立郵件項

  106. privatebool CreateEmailItem(string subjectEmail,string toEmail,string bodyEmail)

  107.        {

  108.            Outlook.Application outlookapp = null;

  109.            Outlook.MailItem email =null;

  110. try

  111.            {

  112. // 建立郵件項,就如你手動點新建郵件一樣

  113.                outlookapp = new Outlook.Application();

  114.                email = outlookapp.CreateItem(Outlook.OlItemType.olMailItem);

  115. // 指定郵件的主題,收件人和內容,就如你在新建郵件窗體中輸入收件人,主題和內容一樣

  116.                email.Subject = subjectEmail;

  117.                email.To = toEmail;

  118.                email.Body = bodyEmail;

  119.                email.Importance = Outlook.OlImportance.olImportanceHigh;

  120. // 傳送郵件,就如你點介面上的傳送郵件操作一樣

  121.                ((Outlook._MailItem)email).Send();

  122.            }

  123. catch(Exception ex)

  124.            {

  125.                MessageBox.Show("傳送郵件的時候失敗,異常資訊為:" + ex.Message);

  126. returnfalse;

  127.            }

  128. finally

  129.            {

  130. // 釋放資源

  131.                ((Outlook._Application)outlookapp).Quit();

  132. if (email != null)

  133.                {

  134.                    Marshal.FinalReleaseComObject(email);

  135.                    email = null;

  136.                }

  137. if (outlookapp != null)

  138.                {

  139.                    Marshal.FinalReleaseComObject(outlookapp);

  140.                    outlookapp = null;

  141.                }

  142.            }

  143. returntrue;

  144.        }



為了測試程式,我新建了一個員工資訊表,表格的格式如下(你當然可以根據自己的需要更改格式):

16180700-e346bdc3a06f4fa096712f6bd32a46c

現在就讓我們看看該程式的執行效果:

16181034-dfa233ce28004084a1173dfb97523d9


四、 小結

  到這裡,本專題的內容就和大家介紹完了,在下一個專題中將向大家介紹下如何通過Office提供的API的來遙控幻燈片。如果大家對本專題中兩個工具的實現原始碼有任何的疑問,都可以在下面留言給我。覺得不錯的話,幫忙贊下,感謝大家的支援。






     本文轉自LearningHard 51CTO部落格,原文連結:http://blog.51cto.com/learninghard/1156852,如需轉載請自行聯絡原作者



相關文章