【问题标题】:programmatically comparing word documents以编程方式比较word文档
【发布时间】:2011-11-23 15:37:20
【问题描述】:

我需要比较两个 office 文档,在这个例子中是两个 word 文档并提供一个差异,这有点类似于 SVN 中显示的内容。没有到那种程度,但至少能够突出差异。

我尝试使用 office COM dll 并做到了这一点..

object fileToOpen = (object)@"D:\doc1.docx";
string fileToCompare = @"D:\doc2.docx";

WRD.Application WA = new WRD.Application();

Document wordDoc = null;

wordDoc = WA.Documents.Open(ref fileToOpen, Type.Missing, Type.Missing, Type.Missing, Type.Missing,      Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
wordDoc.Compare(fileToCompare, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

关于如何进一步进行的任何提示?这将是一个有很多点击量的 Web 应用程序。使用 office com 对象是正确的方法吗,或者还有其他我可以查看的东西吗?

【问题讨论】:

  • 感兴趣的是,SVN如何显示两个二进制文件之间的差异? (AFAIK docx 是一种 zip 存档格式)
  • 选择有问题的两个文件,通常在客户端的同一个文件夹中。你已经安装了tortoiseSVN。您右键单击并转到 TortoiseSVN 菜单并选择 Diff...
  • 是的,我知道该怎么做,但是你会看到什么不同,这有意义吗?
  • 我愿意以一种更明智的方式比较这两个文档。你能推荐一个吗?

标签: c# .net ms-office


【解决方案1】:

您应该使用 Document 类来比较文件并在 Word 文档中打开结果。

using OfficeWord = Microsoft.Office.Interop.Word;

object fileToOpen = (object)@"D:\doc1.docx";
string fileToCompare = @"D:\doc2.docx";

var app = Global.OfficeFile.WordApp;

object readOnly = false;
object AddToRecent = false;
object Visible = false;

OfficeWord.Document docZero = app.Documents.Open(fileToOpen, ref missing, ref readOnly, ref AddToRecent, Visible: ref Visible);

docZero.Final = false;
docZero.TrackRevisions = true;
docZero.ShowRevisions = true;
docZero.PrintRevisions = true;

//the OfficeWord.WdCompareTargetNew defines a new file, you can change this valid value to change how word will open the document
docZero.Compare(fileToCompare, missing, OfficeWord.WdCompareTarget.wdCompareTargetNew, true, false, false, false, false);

【讨论】:

  • 嗨@anderson-rissardi! Compare 方法实际上做了什么?它会在某处打开一些文件吗?因为当我在单元测试中运行它时,我什么也没看到。由于方法返回 void,我应该如何获得结果?
  • 嗨@ditoslav。它打开一个新文件。它是 Word 中的“复制”按钮。打开 MS Word -> 选项卡“审阅”-> 按钮“比较”。是相同的功能,它是生成一个新的文档。您必须保存此新文档。
  • Global.OfficeFile.WordApp 去哪儿了?使用 VS 2019,它显然不再是 Office.Interop.Word 的一部分。
  • @Slagmoth Global.OfficeFile.WordApp 它是一个内部变量。您应该使用应用程序的 Microsoft.Office.Interop.Word.Application
【解决方案2】:

我同意 Joseph 关于区分字符串的问题。我还推荐一个专门构建的 diffing 引擎(这里有几个:Any decent text diff/merge engine for .NET?),它可以帮助您避免一些常见的 diffing 陷阱。

【讨论】:

    【解决方案3】:

    所以我的要求是我必须使用 .Net 库,并且我想避免处理实际文件而是使用流。

    ZipArchive 在 System.IO.Compressed 中

    我所做的并且效果很好的是使用 .Net 中的 ZipArchive 并在跳过 .rels 文件的同时比较内容,因为它似乎是在每个文件创建时随机生成的。这是我的 sn-p:

        private static bool AreWordFilesSame(byte[] wordA, byte[] wordB)
        {
            using (var streamA = new MemoryStream(wordA))
            using (var streamB = new MemoryStream(wordB))
            using (var zipA = new ZipArchive(streamA))
            using (var zipB = new ZipArchive(streamB))
            {
                streamA.Seek(0, SeekOrigin.Begin);
                streamB.Seek(0, SeekOrigin.Begin);
    
                for(int i = 0; i < zipA.Entries.Count; ++i)
                {
                    Assert.AreEqual(zipA.Entries[i].Name, zipB.Entries[i].Name);
    
                    if (zipA.Entries[i].Name.EndsWith(".rels")) //These are some weird word files with autogenerated hashes
                    {
                        continue;
                    }
    
                    var streamFromA = zipA.Entries[i].Open();
                    var streamFromB = zipB.Entries[i].Open();
    
                    using (var readerA = new StreamReader(streamFromA))
                    using (var readerB = new StreamReader(streamFromB))
                    {
                        var bytesA = readerA.ReadToEnd();
                        var bytesB = readerB.ReadToEnd();
                        if (bytesA != bytesB || bytesA.Length == 0)
                        {
                            return false;
                        }
                    }
                }
    
                return true;
            }
        }
    

    【讨论】:

      【解决方案4】:

      您真的应该将文档提取到一个字符串中并对其进行比较。

      您只关心文本更改而不关心格式对吗?

      【讨论】:

      • 一切,即使图像不同。但我会尝试放宽这个要求。
      【解决方案5】:

      对于服务器上的解决方案,或者在没有安装 Word 并使用 COM 工具的情况下运行的解决方案,您可以使用 XmlPowerTools 的 WmlComparer 组件。

      documentation 有点受限,但这里有一个示例用法:

      var expected = File.ReadAllBytes(@"c:\expected.docx");
      var actual = File.ReadAllBytes(@"c:\result.docx");
      var expectedresult = new WmlDocument("expected.docx", expected);
      var actualDocument = new WmlDocument("result.docx", actual);
      var comparisonSettings = new WmlComparerSettings();
      
      var comparisonResults = WmlComparer.Compare(expectedresult, actualDocument, comparisonSettings);
      var revisions = WmlComparer.GetRevisions(comparisonResults, comparisonSettings);
      

      这将显示两个文档之间的差异。

      【讨论】:

      • 您知道 XmlPowerTools 是否可以生成带有差异的结果文档作为“跟踪更改”吗?
      【解决方案6】:

      要在 Word 文档之间进行比较,您需要

      1. 用于操作 Word 文档的库,例如从 Word 文件中读取段落、文本、表格等。你可以试试 Office Interop、OpenXML 或Aspose.Words for .NET
      2. 一种算法/库,用于对从两个 Word 文档中检索到的文本进行实际比较。您可以自己编写或使用 DiffMatchPatch 或类似的库。

      这个问题很老了,现在有更多的解决方案,比如GroupDocs Compare 可用。

      Document Comparison by Aspose.Words for .NET 是一个开源展示项目,使用 Aspose.Words 和 DiffMatchPatch 进行比较。

      我在 Aspose 担任开发人员宣传员。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-07
        • 2021-09-30
        • 1970-01-01
        • 2019-02-23
        相关资源
        最近更新 更多