从Word文档中读取文本时,如何解决后台打开Word的错误?

How to solve the error of Word opening in background when trying to read text from Word documents?

我正在尝试将word文档中的文本字符串读入列表数组,然后在这些文本字符串中搜索单词。然而,问题是,即使我在阅读完文本后关闭了文档,word 文档在 windows 后台打开时仍然保持在 运行 上。

Parallel.ForEach(files, file =>
{
    switch (System.IO.Path.GetExtension(file))
    {
        case ".docx":
            List<string> Word_list = GetTextFromWord(file);
            SearchForWordContent(Word_list, file);
            break;
    }
});

static List<string> GetTextFromWord(string direct)
{
    if (string.IsNullOrEmpty(direct))
    {
        throw new ArgumentNullException("direct");
    }

    if (!File.Exists(direct))
    {
        throw new FileNotFoundException("direct");
    }

    List<string> word_List = new List<string>();
    try
    {
        Microsoft.Office.Interop.Word.Application app =
            new Microsoft.Office.Interop.Word.Application();
        Microsoft.Office.Interop.Word.Document doc = app.Documents.Open(direct);

        int count = doc.Words.Count;

        for (int i = 1; i <= count; i++)
        {
            word_List.Add(doc.Words[i].Text);
        }

        ((_Application)app).Quit();
    }
    catch (System.Runtime.InteropServices.COMException e)
    {
        Console.WriteLine("Error: " + e.Message.ToString());
    }
    return word_List;
}

当您使用 Word Interop 时,您实际上是在启动 Word 应用程序并使用 COM 与其对话。每次通话,甚至阅读 属性,都是一次昂贵的 cross-process 通话。

不用Word也能阅读Word文档。 docx 文档是一个包含 well-defined XML 个文件的 ZIP 包。您可以直接将这些文件读取为 XML,您可以使用 Open XML SDK to read a docx file or use a library like NPOI 来简化 Open XML.

的工作

字数是文档本身的 属性。要使用 Open XML SDK 阅读它,您需要检查文档的 ExtendedFileProperties 部分:

using (var document = WordprocessingDocument.Open(fileName, false))
{
  var words = (int) document.ExtendedFilePropertiesPart.Properties.Words.Text;
}

您会在 MSDN

找到 Open XML 文档,包括 strucrure of Word documents

避免所有者文件

Word 或 Excel 以 ~ 开头的文件是 owner files。这些不是真正的 Word 或 Excel 文件。它们是当有人打开文档进行编辑并包含该用户的登录名时创建的临时文件。这些文件在 Word 正常关闭时被删除,但如果 Word 崩溃或用户没有删除权限,例如在共享文件夹中,这些文件可能会被遗忘。

要避免这些只需要检查文件名是否以~开头。

  • 如果fileName只是文件名和扩展名,fileName.StartsWith("~")就够了
  • 如果fileName是绝对路径,`Path.GetFileName(fileName).StartsWith("~")

尝试过滤文件夹中的此类文件时,事情变得更加棘手。 Directory.EnumerateFilesDirectoryInfo.EnumerateFiles 中使用的模式非常简单,不能排除字符。在调用 EnumerateFiles 之后必须过滤文件,例如:

var dir=new DirectoryInfo(folderPath);

foreach(var file in dir.EnumerateFiles("*.docx"))
{
    if (!file.Name.StartsWith("~"))
    {
        ...
    }
}

或者,使用 LINQ:

var dir=new DirectoryInfo(folderPath);
var files=dir.EnumerateFiles("*.docx")
             .Where(file=>!file.Name.StartsWith("~"));
foreach(var file in files)
{
    ...
}

如果以独占方式打开文件进行编辑,枚举仍然会失败。为了避免异常,可以使用 EnumerationOptions.IgnoreInaccessible 参数来跳过锁定的文件:

var dir=new DirectoryInfo(folderPath);
var options=new EnumerationOptions 
            { 
                IgnoreInaccessible =true
            };
var files=dir.EnumerateFiles("*.docx",options)
             .Where(file=>!file.Name.StartsWith("~"));

一个选择是

  • 列表项
  • 列表项