1. 概述

Apache Tika 是一个强大的工具包,用于从各种文档类型(如 Word、Excel、PDF)甚至多媒体文件(如 JPEG、MP4)中提取内容和元数据

所有基于文本和多媒体的文件都可以通过统一接口解析,这使得 Tika 成为内容分析领域的多功能利器。本文将介绍 Apache Tika 的核心功能,包括其解析 API 和文档类型自动检测机制,并通过实际示例演示库的使用方法。

2. 快速开始

使用 Apache Tika 解析文档只需添加一个 Maven 依赖:

<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-parsers</artifactId>
    <version>1.17</version>
</dependency>

最新版本可在 Maven 中央仓库 查询。

3. 解析器 (Parser) API

解析器 API 是 Apache Tika 的核心,它封装了底层解析操作的复杂性。该 API 依赖一个核心方法:

void parse(
  InputStream stream, 
  ContentHandler handler, 
  Metadata metadata, 
  ParseContext context) 
  throws IOException, SAXException, TikaException

参数说明:

  • stream - 待解析文档的输入流
  • handler - 接收 XHTML SAX 事件的内容处理器,负责将事件转换为特定格式的输出
  • metadata - 传递解析器元数据属性的对象
  • context - 携带上下文信息的解析上下文,用于定制解析过程

⚠️ 异常处理:

  • IOException:输入流读取失败
  • TikaException:文档无法解析
  • SAXException:处理器事件处理失败

Tika 底层会复用 Apache POI 或 PDFBox 等现有解析库,因此大部分 Parser 实现类只是这些外部库的适配器。在后续章节中,我们将看到如何利用 handlermetadata 提取文档内容和元数据。

为简化操作,可直接使用门面类 Tika 访问解析器 API 的功能。

4. 自动检测机制

Apache Tika 能基于文档内容自动检测类型和语言,无需依赖额外信息。

4.1. 文档类型检测

文档类型检测通过 Detector 接口的实现类完成,其核心方法:

MediaType detect(java.io.InputStream input, Metadata metadata) 
  throws IOException

该方法接收文档及其元数据,返回表示文档类型的 MediaType 对象。检测器依赖以下信息源:

  • Magic Bytes:文件开头的特殊字节模式(如 PDF 的 %PDF
  • 元数据属性:文档内置的元数据信息
  • 委托检测:调用更专业的检测器

默认检测器的检测顺序:

  1. 优先使用 Magic Bytes
  2. 次选元数据属性
  3. 最后通过服务加载机制尝试所有可用检测器

4.2. 语言检测

Tika 还能在无元数据辅助的情况下识别文档语言。早期版本使用 LanguageIdentifier,但该类已被废弃,当前推荐使用基于 Web 服务的语言检测方案。

语言检测服务通过抽象类 LanguageDetector 的子类提供,可集成 Google Translate 或 Microsoft Translator 等在线翻译服务。由于篇幅限制,此处不展开详述。

5. 实战演练

本节通过实际示例演示 Tika 的核心功能。所有示例代码封装在以下工具类中:

public class TikaAnalysis {
    // 示例方法
}

5.1. 文档类型检测

使用 Detector 检测文档类型:

public static String detectDocTypeUsingDetector(InputStream stream) 
  throws IOException {
    Detector detector = new DefaultDetector();
    Metadata metadata = new Metadata();

    MediaType mediaType = detector.detect(stream, metadata);
    return mediaType.toString();
}

测试用例:类路径下有一个伪装成 .txt 的 PDF 文件 tika.txt(实际为 PDF 格式)

@Test
public void whenUsingDetector_thenDocumentTypeIsReturned() 
  throws IOException {
    InputStream stream = this.getClass().getClassLoader()
      .getResourceAsStream("tika.txt");
    String mediaType = TikaAnalysis.detectDocTypeUsingDetector(stream);

    assertEquals("application/pdf", mediaType);

    stream.close();
}

即使文件扩展名被篡改,Tika 仍能通过文件开头的 Magic Bytes 正确识别 PDF 类型。

更简洁的实现方式(使用 Tika 门面类):

public static String detectDocTypeUsingFacade(InputStream stream) 
  throws IOException {
 
    Tika tika = new Tika();
    String mediaType = tika.detect(stream);
    return mediaType;
}

5.2. 内容提取

使用 Parser API 提取文档内容:

public static String extractContentUsingParser(InputStream stream) 
  throws IOException, TikaException, SAXException {
 
    Parser parser = new AutoDetectParser();
    ContentHandler handler = new BodyContentHandler();
    Metadata metadata = new Metadata();
    ParseContext context = new ParseContext();

    parser.parse(stream, handler, metadata, context);
    return handler.toString();
}

测试用例:类路径下的 Word 文档 tika.docx 包含以下内容:

Apache Tika - a content analysis toolkit
The Apache Tika™ toolkit detects and extracts metadata and text ...

验证提取结果:

@Test
public void whenUsingParser_thenContentIsReturned() 
  throws IOException, TikaException, SAXException {
    InputStream stream = this.getClass().getClassLoader()
      .getResourceAsStream("tika.docx");
    String content = TikaAnalysis.extractContentUsingParser(stream);

    assertThat(content, 
      containsString("Apache Tika - a content analysis toolkit"));
    assertThat(content, 
      containsString("detects and extracts metadata and text"));

    stream.close();
}

简化版实现(使用 Tika 门面类):

public static String extractContentUsingFacade(InputStream stream) 
  throws IOException, TikaException {
 
    Tika tika = new Tika();
    String content = tika.parseToString(stream);
    return content;
}

5.3. 元数据提取

使用 Parser API 提取元数据:

public static Metadata extractMetadatatUsingParser(InputStream stream) 
  throws IOException, SAXException, TikaException {
 
    Parser parser = new AutoDetectParser();
    ContentHandler handler = new BodyContentHandler();
    Metadata metadata = new Metadata();
    ParseContext context = new ParseContext();

    parser.parse(stream, handler, metadata, context);
    return metadata;
}

测试用例:类路径下的 Excel 文件 tika.xlsx

@Test
public void whenUsingParser_thenMetadataIsReturned() 
  throws IOException, TikaException, SAXException {
    InputStream stream = this.getClass().getClassLoader()
      .getResourceAsStream("tika.xlsx");
    Metadata metadata = TikaAnalysis.extractMetadatatUsingParser(stream);

    assertEquals("org.apache.tika.parser.DefaultParser", 
      metadata.get("X-Parsed-By"));
    assertEquals("Microsoft Office User", metadata.get("Author"));

    stream.close();
}

简化版实现(使用 Tika 门面类):

public static Metadata extractMetadatatUsingFacade(InputStream stream) 
  throws IOException, TikaException {
    Tika tika = new Tika();
    Metadata metadata = new Metadata();

    tika.parse(stream, metadata);
    return metadata;
}

6. 总结

本文系统介绍了 Apache Tika 的内容解析能力。通过 ParserDetector API,我们可以实现:

  • ✅ 自动检测文档类型
  • ✅ 提取文档内容
  • ✅ 解析文档元数据

对于高级场景,可通过自定义 ParserDetector 实现更精细的解析控制。完整示例代码可在 GitHub 获取。


原始标题:Content Analysis with Apache Tika