C#比較兩個word文檔的內容

 本文歡迎轉載,但必須在文章顯眼處保留原文地址

 http://www.cnblogs.com/Ss_Andy/archive/2010/11/02/1866762.html

       最近在開發的項目中,又遇到一個和word有關的問題,就是用戶修改了一個word文檔的內容後,需要將這個文檔另一個事生成好的文檔進行對比,看是否有修改.從而決定要不要提示用戶修改另一文檔..

      word文檔的對比不像一般的txt文件,直接用File類進行讀取操作.由於word的編碼是沒有公開的,所以想讀取word裏面的內容,還是得需要靠微軟提供的office組件進行操作,不過這也麻煩,裏面所提供幾個讀取的方法,好像都只是能讀到純文本而以,帶格式都會給過濾掉,一般富格式都沒有正常顯示出來(比如flash,圖片,表格),也許本人孤陋寡聞,在office組件中沒有找到完美的解決方案,不過好在經過了幾天的時間,也解決了這個問題,下面就說說解決方案吧!

 

       目前想到的就有三種方式可以解決,下面爲你一一道來.

       一.第一種也是最簡單方式,也是我第一時間想到的解決方案,可以將word文檔轉換成html文件,然後再將html文件轉換成txt文件,然後用我們經常使用操作文件類File進行讀取裏面的文本(這時會包括html裏面的標籤,這樣才能保留原先的格式),進行對比,這時讀到的全是純文檔,在C#裏面就直接當成字符串處理就得了!這個應該很容易很好理解吧!不過據比較牛X的同事說,因爲word的功能非常強大,所以直接轉換成html的話,可能會造成某些數據的丟失.PS:目前本人試過幾次,都沒有發現丟失的情況,可能測試的次數過少,或者說沒有包函大量的數據吧!

           優點:易懂,簡單.

           缺點:有可能造成丟失數據的風險.

      二.第二種方式有版本要求,需要是office2007或者2007以上的版本,2007以上的文檔保存文件後綴是docx,你可以使用C#將他進行重命名,改成壓縮文件的格式,然後再進行解壓,你會看到很多資源文件(你可以先手動操作一下,看明白流程),然後再讀取裏面相關的xml文件,進行對比,但由於生成的文件過多,這個過程應該是相當煩瑣的,所以,本人沒有實踐過,但知道肯定是可以實現的.同時要求電腦上要裝有解壓程序(這個一般都會有拉,不過還是要考慮的,)

           優點:應該是可以較完美的解決問題.也不會造成丟失數據的風險.

          缺點:操作煩瑣,要弄明白所解壓後的相關資源文件,加上對比的東西會比較多,這個過程相當相當煩瑣.

      三.第三種,自認爲是最完美的解決方法,目前項目也打算使用這種方式解決問題,下面說說具體的解決過程.

          優點:性能不錯,也應該是可以完美解決問題,目前還沒有發現別的問題.所有比較都讓微軟幫我們做了.

          缺點:還沒發現..

          1.先添加引用Microsoft.Office.Interop.Word.

           2.接着讓Microsoft.Office.Interop.Word.Application加載其中一個doc文檔

              private Microsoft.Office.Interop.Word.Application _wordApplication;
              private Microsoft.Office.Interop.Word.Document _wordDocument;
              object nullobj = System.Reflection.Missing.Value;
              public void LoadWord(string fileName)
             {
                   this._wordApplication = new Microsoft.Office.Interop.Word.Application();
                  object objFile = fileName;
                  this._wordDocument = _wordApplication.Documents.Open(ref objFile, ref nullobj, ref nullobj,
                  ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
                   ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
               }

        3.再使用Microsoft.Office.Interop.Word.Application裏面的一個比較功能

             object compareTarget = Microsoft.Office.Interop.Word.WdCompareTarget.wdCompareTargetSelected;
            object addToRecentFiles = false;
            _wordDocument.Compare(file, ref nullobj, ref compareTarget, ref nullobj, ref nullobj, ref addToRecentFiles, ref nullobj, ref nullobj);

          簡單介紹一下這個Compare函數的功能,file就是你要對比的第二文件,

          compareTarget =Microsoft.Office.Interop.Word.WdCompareTarget.wdCompareTargetSelected;就是將對比後的結果加在第二個文檔裏面(其實就是修訂拉,用過word修訂功能的人都知道,他就是把你做的修改顯示在word裏面,當你鼠標移上去,他就會提示你,哪個用戶在什麼時候做了什麼事情(比如:張三2010-11-1 19:00:00 刪除ABC),可能這樣說,好像很模糊一樣,大家自己試一下就一目瞭解拉! 當然,我們要的不是這樣,我們要的是直接告訴我們,哪裏不一樣!不要讓他去修改第二個文檔.但我找了很久,都沒有相關的函數可以讀取到這些修訂信息.好在前陣子用過dsoframer.ocx這個web版本word控件,裏面有提供了一個方法,可以讀取到文檔中的修訂信息(具體的dsoframer.ocx使用方法,可以上網找,有好多相關資料的,也可以留言大家討論討論哈),下面貼出dsoframer獲取修訂信息的具體代碼

 

         先讓你界面上的dsoframer控件加載你的第二個文檔,就是你調用Compare這個方法時傳進去的file.然後下面再進行獲取相關數據.

         var vCount = document.all.hideWord.GetRevCount();  //修改條數,比如刪除一段話,vCount就是=1

         for(var i=1;i<=vCount;i++){

           //循環獲取數據,i是表示第幾條,2是表示做了什麼操作  vOpt=1表示插入,=2表示刪除

          //可以把下面的2改成1,就是獲取是哪個用戶做了修改,好像1是獲取用戶吧,哈哈,自己動手試下吧!

           var vOpt = document.all.hideWord.GetRevInfo(i,2);

           var context =  document.all.hideWord.GetRevInfo(i,3);  //3是表示獲取修改了什麼信息,比如用戶刪除了ABC,這裏context就會等於"ABC"

         }

 

看了上面這段代碼,應該知道,我們是可以獲取文檔哪裏不一樣的了!因爲在調用Compare這個方法的時候,微軟已經幫我們做了比較了,我們只是把相關的信息提取出來而以.

       不過上面的代碼太片斷了,我還是貼出我在項目中的代碼吧,可能看上去比較清晰點..

 

//我項目中判斷文檔有沒有改變,根據您自己的需求,可能這裏會和我不一樣!
function IsChange()
{
      var vCount = document.all.hideWord.GetRevCount();
      if(vCount%2!=0) return true;
      var vOpt;
      var Data="";
      for(var i=1;i<=vCount;i++)
      {
            //類型判斷是否修改
           
            //1:插入
            //2:刪除
            vOpt = document.all.hideWord.GetRevInfo(i,2);
            if(vOpt=="2") 
            {
                if(i==vCount) return;  //如果刪除是最後一個,就表示有修改文檔
                var nextvOpt = document.all.hideWord.GetRevInfo(i+1,2);
                if(nextvOpt=="2") return  true;//如果刪除下面還是刪除,就表示有修改文檔
            }
            if(vOpt=="1")
            {
                if((i+1)<=vCount)
                {
                    var nextvOpt = document.all.hideWord.GetRevInfo(i+1,2);
                     if(nextvOpt=="1") return  true;//如果插入下面還是插入,就表示有修改文檔
                }
            }
       }

       //下面這一段你可以不用管,是因爲項目原因,需要忽略文檔中的個別字符.
       for(var i=1;i<=vCount;i++){
            var context =  document.all.hideWord.GetRevInfo(i,3);
            var nextContext = document.all.hideWord.GetRevInfo(i+1,3);
            var replaceContext = context.replace("稅目","品目")
            if(replaceContext!=nextContext) return true;
            i++;
       }
       return false;
}

 

簡單解釋一下,比如文件A裏面是abc,文檔B裏面是abd,你用上面的方法讀取第二文檔的修訂信息時,將是兩條數據!第一條:刪除了c. 第二條:插入了d

就是說你所有的修改,他都說先刪除,再插入的,會有兩條記錄的!當然,如果沒有刪除舊的數據,只是添加,就是一條,刪除也是一樣!但是修改就是兩條數據了.

 

根據上我面的代碼,你可能會發現,修訂信息是提取到了,但第二文檔中也顯示了修訂信息,我們要的應該只是對比,而不要改到第二個文檔.那這時可以使用office組件裏面提供的一個方法進行接受修訂信息(等會我會貼出操作office組件的類).

PS:如果第二word文檔裏面已經存在的修訂信息的話,調用比較的方法會報錯,所以我們在比較前,可以先讓第二文檔設置成接受修訂(即使你沒有修訂信息也不會報錯)

 

下面是我的 操作office組件的類(刪除了大量與本貼無關的代碼)

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace TariffItemLib.Common
{

    public class WordHelper
    {
        private Microsoft.Office.Interop.Word.Application _wordApplication;
        private Microsoft.Office.Interop.Word.Document _wordDocument;
        object nullobj = System.Reflection.Missing.Value;
        public WordHelper(string fileName)
        {
            this._wordApplication = new Microsoft.Office.Interop.Word.Application();
            object objFile = fileName;
            this._wordDocument = _wordApplication.Documents.Open(ref objFile, ref nullobj, ref nullobj,
                ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
                ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
        }
        /// <summary>
        /// 進行與類創建時指定的文件比較,然後將差異顯示在file,並保存退出
        /// </summary>
        /// <param name="file"></param>
        public void Compare(string file)
        {
            object compareTarget = Microsoft.Office.Interop.Word.WdCompareTarget.wdCompareTargetSelected;
            object addToRecentFiles = false;
            _wordDocument.Compare(file, ref nullobj, ref compareTarget, ref nullobj, ref nullobj, ref addToRecentFiles, ref nullobj, ref nullobj);

            object objfile = file;
            this._wordDocument = _wordApplication.Documents.Open(ref objfile, ref nullobj, ref nullobj,
               ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
               ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
            _wordApplication.NormalTemplate.Saved = true;
            _wordDocument.Save();
            object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
            _wordApplication.Quit(ref saveOption,ref nullobj,ref nullobj);
        }

        /// <summary>
        /// 接受修訂
        /// 需重新創建WordHelper類,指定文件
        /// </summary>
        public void AcceptRevised()
        {
            _wordDocument.AcceptAllRevisions();
            _wordDocument.Save();
            object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
            _wordApplication.Quit(ref saveOption, ref nullobj, ref nullobj);
        }
    }
}

 

 

 上面的文字,我看上去我自己很清晰,如果是沒有研究過這個問題的朋友看上去一定很像炒麪, 但你如果研究過這個問題的話,應該還是可以看懂的!如果有不明白的話,可以留言我們討論討論吧!呵

 大概的思路重新寫一下:用office組件進行比較,比較的時候,會將不一樣的地方使用修訂(也有人叫筆記留痕)方式顯示在第二個文檔裏面,然後再使用dsoframer控件加載第二個有修訂信息的文檔,進行讀取.最後再讓第二文檔接受修訂.

大概是這樣的咯,不過在真正開發的時候,會遇到很多小問題的,如果遇到的朋友不妨提出來大家討論討論..

 

 

上面的三種方法是自己想的,不知有沒有更好的方法,知道的朋友不妨通知一聲,在下感激不盡..

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章