如何在 C# 中从 MS Office 文档中提取文本
Posted
技术标签:
【中文标题】如何在 C# 中从 MS Office 文档中提取文本【英文标题】:How to extract text from MS office documents in C# 【发布时间】:2010-11-03 22:01:41 【问题描述】:我试图使用 C# 从 MS Word(.doc、.docx)、Excel 和 Powerpoint 中提取文本(字符串)。我在哪里可以找到一个免费且简单的 .Net 库来阅读 MS Office 文档? 我尝试使用 NPOI,但没有获得有关如何使用 NPOI 的示例。
【问题讨论】:
【参考方案1】:对于 Microsoft Word 2007 和 Microsoft Word 2010 (.docx) 文件,您可以使用 Open XML SDK。这个 sn-p 代码将打开一个文档并将其内容作为文本返回。对于任何试图使用正则表达式来解析 Word 文档内容的人来说,它尤其有用。要使用此解决方案,您需要参考 DocumentFormat.OpenXml.dll,它是 OpenXML SDK 的一部分。
见:http://msdn.microsoft.com/en-us/library/bb448854.aspx
public static string TextFromWord(SPFile file)
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
StringBuilder textBuilder = new StringBuilder();
using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(file.OpenBinaryStream(), false))
// Manage namespaces to perform XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", wordmlNamespace);
// Get the document part from the package.
// Load the XML in the document part into an XmlDocument instance.
XmlDocument xdoc = new XmlDocument(nt);
xdoc.Load(wdDoc.MainDocumentPart.GetStream());
XmlNodeList paragraphNodes = xdoc.SelectNodes("//w:p", nsManager);
foreach (XmlNode paragraphNode in paragraphNodes)
XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t", nsManager);
foreach (System.Xml.XmlNode textNode in textNodes)
textBuilder.Append(textNode.InnerText);
textBuilder.Append(Environment.NewLine);
return textBuilder.ToString();
【讨论】:
@adrianbanks 我觉得这个答案目前比接受的答案更好,因为接受的答案在某些版本的 Windows 上不起作用,而且 IFilter 是一个已弃用的接口。当然,在撰写阿德里安的帖子时,情况并非如此。 SPFile 怎么样?您在函数中输入的参数就是这种类型,我能找到的只是 Microsoft.Sharepoint.dll -> 中的 Microsoft.Sharepoint 命名空间,而且这个 dll 不容易找到。你参考了什么来获取 SPFile? @user867703 您不必使用 SPFile。这是一个例子。您可以使用任何 .docx 文件(以二进制流形式打开)。看看 WordprocessingDocument.Open 方法,这是重要的方法。 我只是将 SPFile 更改为路径(字符串),并且在 open 方法中我只使用了路径 -> 它可以工作。解决方案非常清晰和简单。 @KyleM 这看起来不像在 64 位系统上为我工作。我找不到 64 位系统的 DocumentFormat.OpenXML dll。添加32位不起作用。还是我做错了什么?【参考方案2】:使用 PInvokes,您可以使用IFilter 接口(在 Windows 上)。许多常见文件类型的 IFilter 随 Windows 一起安装(您可以使用 this 工具浏览它们。您可以只要求 IFilter 从文件中返回文本。有几组示例代码(here 是其中之一)这样的例子)。
【讨论】:
有趣...一个非常偷偷摸摸的解决方案:) 并非如此。这是 Windows 上的索引服务使用的机制,我认为桌面搜索也使用它。我用它来索引 pdf(通过安装 Adobe IFilter - adobe.com/support/downloads/detail.jsp?ftpID=2611)、所有类型的 Office 文档(这些 IFilter 随 Windows 一起安装)和其他几种文件类型。当它工作时,它工作得很好。但有时,您不会从 IFilter 收到任何文本,也没有理由说明原因。 我使用了 pInvoke,发现它非常棒。要从任何文档中提取文本,我们所要做的就是确保在机器上安装了适当的 IFilter(或下载并安装)。我喜欢这个文章和示例表单代码项目看看这个codeproject.com/KB/cs/IFilter.aspx for MS Office 2007 这里是 MS Office 2007 过滤器包microsoft.com/downloads/… 可以,只要您安装了 PDF iFilter。您可以通过安装 Acrobat Reader(随 iFilter 一起安装)或单独安装 iFilter (adobe.com/support/downloads/detail.jsp?ftpID=4025) 来完成此操作。 [注意:其他 PDF iFilter 可用:)] 2 个快速问答 - a) 我目前正在使用此处列出的方法 - codeproject.com/KB/cs/PDFToText.aspx 从 PDF 中提取文本。使用 IFilter 会有什么不同? b)在您链接的 IFilter 方法中,作者执行以下操作: TextReader reader=new FilterReader(fileName);我在 ASP.NET 中使用 FileUpload 控件,但我无法获取文件名的路径,因为为了安全起见,它没有在服务器端公开。我只能对服务器端的 fileUpload 控件执行以下操作: Stream str = fileUpload1.FileContent;字节 b[] = fileUpload1.FileBytes;【参考方案3】:Tika 非常有用,可以轻松从不同类型的文档中提取文本,包括 microsoft office 文件。
您可以使用这个由 Kevin Miller 制作的精美艺术品 http://kevm.github.io/tikaondotnet/
只需添加这个 NuGet 包 https://www.nuget.org/packages/TikaOnDotNet/
然后,这一行代码就能发挥作用:
var text = new TikaOnDotNet.TextExtractor().Extract("fileName.docx / pdf / .... ").Text;
【讨论】:
这是你需要的包:nuget.org/packages/TikaOnDotnet.TextExtractor 这里值得注意的是,这实际上是通过 IKVM 运行 Apache Tika (java),IKVM 是 java 的 .net 运行时,所以它不是一个轻量级的解决方案。 (40MB 的二进制文件,基本上是一个完整的 java 运行时)【参考方案4】:让我稍微纠正一下 KyleM 给出的答案。我刚刚添加了两个额外节点的处理,这会影响结果:一个负责“\t”的水平制表,另一个负责“\v”的垂直制表。代码如下:
public static string ReadAllTextFromDocx(FileInfo fileInfo)
StringBuilder stringBuilder;
using(WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(dataSourceFileInfo.FullName, false))
NameTable nameTable = new NameTable();
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(nameTable);
xmlNamespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
string wordprocessingDocumentText;
using(StreamReader streamReader = new StreamReader(wordprocessingDocument.MainDocumentPart.GetStream()))
wordprocessingDocumentText = streamReader.ReadToEnd();
stringBuilder = new StringBuilder(wordprocessingDocumentText.Length);
XmlDocument xmlDocument = new XmlDocument(nameTable);
xmlDocument.LoadXml(wordprocessingDocumentText);
XmlNodeList paragraphNodes = xmlDocument.SelectNodes("//w:p", xmlNamespaceManager);
foreach(XmlNode paragraphNode in paragraphNodes)
XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t | .//w:tab | .//w:br", xmlNamespaceManager);
foreach(XmlNode textNode in textNodes)
switch(textNode.Name)
case "w:t":
stringBuilder.Append(textNode.InnerText);
break;
case "w:tab":
stringBuilder.Append("\t");
break;
case "w:br":
stringBuilder.Append("\v");
break;
stringBuilder.Append(Environment.NewLine);
return stringBuilder.ToString();
【讨论】:
如果w:p里面有图片怎么提取?【参考方案5】:使用 Microsoft Office 互操作。它免费且流畅。这是我如何从文档中提取所有单词的方法。
using Microsoft.Office.Interop.Word;
//Create Doc
string docPath = @"C:\docLocation.doc";
Application app = new Application();
Document doc = app.Documents.Open(docPath);
//Get all words
string allWords = doc.Content.Text;
doc.Close();
app.Quit();
然后对单词做任何你想做的事情。
【讨论】:
啊,我的朋友太棒了。这现在应该是公认的答案,其余的已经过时了。 这很容易,但也很慢的解决方案。 Open XML 的速度要快“数千倍”。 它是免费的 - 它不需要你安装 Word 吗? @Chris: 来自 Matt Burland 的 catch22,我如何在 Linux 服务器上运行它? ;)【参考方案6】:聚会有点晚了,但是——现在你不需要下载任何东西——所有东西都已经安装了 .NET: (只需确保添加对 System.IO.Compression 和 System.IO.Compression.FileSystem 的引用)
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml;
using System.Text;
using System.IO.Compression;
public static class DocxTextExtractor
public static string Extract(string filename)
XmlNamespaceManager NsMgr = new XmlNamespaceManager(new NameTable());
NsMgr.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
using (var archive = ZipFile.OpenRead(filename))
return XDocument
.Load(archive.GetEntry(@"word/document.xml").Open())
.XPathSelectElements("//w:p", NsMgr)
.Aggregate(new StringBuilder(), (sb, p) => p
.XPathSelectElements(".//w:t|.//w:tab|.//w:br", NsMgr)
.Select(e => switch (e.Name.LocalName) case "br": return "\v"; case "tab": return "\t"; return e.Value; )
.Aggregate(sb, (sb1, v) => sb1.Append(v)))
.ToString();
【讨论】:
这看起来是一个很好的解决方案,但我无法完成这项工作,因为我遇到了一个错误:Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory.
该消息似乎是一个 ZipFile
压缩文件(即本例中的 docx 文件)已损坏的概念......
这不起作用,因为它不保留行尾。【参考方案7】:
简单!
这两个步骤将带您到达那里:
1) 使用Office Interop library 将 DOC 转换为 DOCX 2)使用DOCX2TXT从新的DOCX中提取文本
1) 的链接很好地解释了如何进行转换,甚至还有代码示例。
2) 的替代方法是在 C# 中解压缩 DOCX 文件并扫描您需要的文件。您可以阅读 ZIP 文件的结构here。
编辑:啊,是的,我忘了指出,正如 Skurmedel 在下面所做的那样,您必须在要进行转换的系统上安装 Office。
【讨论】:
Office 互操作库唯一可悲的部分是您需要安装 Office。Interop
可用,但应尽可能避免使用。
Microsoft Word 12.0 对象库 --> 这不在我的添加引用列表中,右键单击添加引用。是否有另一种方法必须输入 Microsoft Word 12.0 对象库,以便我可以阅读 word 文档。
互操作在 Godaddy 主机中不起作用。 Godday 不支持 Office。【参考方案8】:
我曾经做过一个 docx 文本提取器,非常简单。基本上 docx 和我认为的其他(新)格式是一个带有一堆 XML 文件的 zip 文件。可以使用 XmlReader 并仅使用 .NET 类来提取文本。
我没有代码了,看起来:(,但我找到了一个有类似solution的人。
如果您需要阅读 .doc 和 .xls 文件,也许这对您不可行,因为它们是二进制格式,可能更难解析。
还有OpenXML SDK,虽然仍在 CTP 中,由 Microsoft 发布。
【讨论】:
这真是太棒了!我已经完成了 docx,剩下的呢? 您可以“连接”到 xslx 文件,就像我认为使用 ODCB 的数据库一样。我认为一个非常麻烦的解决方案。我不知道如何阅读 .doc 文件或 .xls 文件,所以我无法帮助你。这是 .xls 文件的参考:sc.openoffice.org/excelfileformat.pdf 我在 XLSX 上找不到比规范本身更好的东西了:ecma-international.org/publications/files/ECMA-ST/…【参考方案9】:如果您正在寻找 asp.net 选项,除非您在服务器上安装 Office,否则互操作将无法工作。即使那样,微软也表示不要这样做。
我使用了 Spire.Doc,效果很好。 Spire.Doc download 它甚至可以读取实际上是 .txt 但保存为 .doc 的文档。他们有免费和付费版本。您还可以获得一个试用许可证,该许可证会从您创建的文档中删除一些警告,但我没有创建任何警告,只是搜索了它们,因此免费版本就像一个魅力。
【讨论】:
Erik Felde,你能给 Spire.Doc 上的 asp.net 举一些例子吗【参考方案10】:在 C# 中从 Office 文档中提取文本的合适选项之一是 GroupDocs.Parser for .NET API。以下是提取简单文本和格式化文本的代码示例。
提取文本
// Create an instance of Parser class
using(Parser parser = new Parser("sample.docx"))
// Extract a text into the reader
using(TextReader reader = parser.GetText())
// Print a text from the document
// If text extraction isn't supported, a reader is null
Console.WriteLine(reader == null ? "Text extraction isn't supported" : reader.ReadToEnd());
提取格式化文本
// Create an instance of Parser class
using (Parser parser = new Parser("sample.docx"))
// Extract a formatted text into the reader
using (TextReader reader = parser.GetFormattedText(new FormattedTextOptions(FormattedTextMode.html)))
// Print a formatted text from the document
// If formatted text extraction isn't supported, a reader is null
Console.WriteLine(reader == null ? "Formatted text extraction isn't suppported" : reader.ReadToEnd());
披露:我在 GroupDocs 担任开发人员宣传员。
【讨论】:
以上是关于如何在 C# 中从 MS Office 文档中提取文本的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MFC 中支持多种文档类型,例如 MS Office 应用程序或 Visual Studio
如何以编程方式重新启用 MS Office 禁用文件列表中的文档
如何在 C# 中使用 Microsoft.Office.Interop.Excel.Application 保存打开的文档?