Apache Tika 教程

Apache Tika 是一个内容分析工具包,用于检测和提取文档中的元数据和文本内容。它支持超过1000种文件格式。

1. 核心特性

  • 格式检测:自动识别文件类型(MIME)

  • 内容提取:提取纯文本内容

  • 元数据提取:获取作者、创建日期等信息

  • 语言检测:识别文档语言

2. 快速开始

Maven 依赖

XML 复制代码
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>2.9.1</version>
</dependency>
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-parsers-standard-package</artifactId>
    <version>2.9.1</version>
</dependency>

基础用法

java 复制代码
import org.apache.tika.Tika;
import java.io.File;
import java.io.InputStream;

// 最简单的方式
Tika tika = new Tika();
String text = tika.parseToString(new File("document.pdf"));
System.out.println(text);

3. 主要使用方式

方式一:Tika API(推荐新手)

java 复制代码
Tika tika = new Tika();

// 文件类型检测
String mimeType = tika.detect(new File("test.pdf"));

// 解析文件
String content = tika.parseToString(new File("test.docx"));

// 解析流
try (InputStream is = new FileInputStream("test.pptx")) {
    String content = tika.parseToString(is);
}

方式二:Parser API(更精细控制)

java 复制代码
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.sax.BodyContentHandler;

AutoDetectParser parser = new AutoDetectParser();
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();

try (InputStream stream = new FileInputStream("document.pdf")) {
    parser.parse(stream, handler, metadata);
    
    // 获取文本
    String text = handler.toString();
    
    // 获取元数据
    String author = metadata.get("Author");
    String date = metadata.get("Creation-Date");
}

方式三:RecursiveParser(递归嵌入文件)

java 复制代码
RecursiveParserWrapper wrapper = new RecursiveParserWrapper(
    new AutoDetectParser()
);

try (InputStream stream = new FileInputStream("embedded.doc")) {
    wrapper.parse(stream, new BodyContentHandler(), new Metadata());
    
    for (RecursiveParserWrapperHandler.MetadataWithContent mwc : 
         wrapper.getMetadataList()) {
        System.out.println("File: " + mwc.getMetadata().get(Metadata.RESOURCE_NAME_KEY));
        System.out.println("Content: " + mwc.getContentHandler().toString());
    }
}

4. 常见文件格式支持

格式 扩展名 支持程度
PDF .pdf 完整
Word .doc, .docx 完整
Excel .xls, .xlsx 完整
PowerPoint .ppt, .pptx 完整
HTML/XML .html, .xml 完整
图片 .jpg, .png, .gif 文本+元数据
邮件 .eml, .msg 完整
RTF .rtf 完整
TXT .txt 完整

5. 配置选项

设置最大字符串长度

java 复制代码
// 默认100k字符
BodyContentHandler handler = new BodyContentHandler(500000);

自定义配置

java 复制代码
import org.apache.tika.config.TikaConfig;

TikaConfig config = new TikaConfig();
Tika tika = new Tika(config);

// 或使用自定义配置文件
TikaConfig config = new TikaConfig("my-tika-config.xml");

排除特定解析器

java 复制代码
Parsers parsers = new Parsers();
Set<MediaType> excluded = Set.of(
    MediaType.APPLICATION_ZIP,
    MediaType.APPLICATION_PDF
);
AutoDetectParser parser = new AutoDetectParser(
    parsers.getParsers(excluded)
);

6. 高级功能

语言检测

java 复制代码
import org.apache.tika.language.LanguageIdentifier;

String text = "This is an English sentence.";
LanguageIdentifier identifier = new LanguageIdentifier(text);
String language = identifier.getLanguage(); // "en"

提取特定元数据

java 复制代码
Metadata metadata = new Metadata();
// 常用元数据字段
metadata.names().forEach(name -> {
    System.out.println(name + ": " + metadata.get(name));
});

// 标准字段
metadata.get(Metadata.AUTHOR);
metadata.get(Metadata.CREATION_DATE);
metadata.get(Metadata.TITLE);

嵌入式内容处理

java 复制代码
EmbeddedDocumentExtractor extractor = new EmbeddedDocumentExtractor() {
    @Override
    public boolean shouldParseEmbedded(Metadata metadata) {
        return true;
    }
    
    @Override
    public void parseEmbedded(InputStream stream, ContentHandler handler, 
                              Metadata metadata, boolean outputHtml) {
        // 处理嵌入式文件
    }
};

7. 命令行工具

Tika 提供了命令行版本:

bash 复制代码
# 下载 tika-app.jar
wget https://archive.apache.org/dist/tika/2.9.1/tika-app-2.9.1.jar

# 提取文本
java -jar tika-app-2.9.1.jar --text document.pdf

# 检测MIME类型
java -jar tika-app-2.9.1.jar --detect file.pdf

# 提取元数据
java -jar tika-app-2.9.1.jar --metadata document.docx

# 列出支持的类型
java -jar tika-app-2.9.1.jar --list-supported-types

# JSON输出
java -jar tika-app-2.9.1.jar --json document.pdf

8. 性能优化

复用解析器实例

java 复制代码
// 正确做法 - 单例
private static final AutoDetectParser PARSER = new AutoDetectParser();

// 错误做法 - 每次新建
// AutoDetectParser parser = new AutoDetectParser(); // 消耗资源

使用ParseContext缓存

java 复制代码
ParseContext context = new ParseContext();
context.set(Parser.class, PARSER);

// 复用context
parser.parse(stream, handler, metadata, context);

配置内存限制

java 复制代码
TikaConfig config = TikaConfig.getDefaultConfig();
// 修改配置限制解析时间和内存

9. 常见问题解决

中文乱码

java 复制代码
// 确保使用正确的字符编码
BodyContentHandler handler = new BodyContentHandler(-1);
// 手动设置编码
String content = new String(text.getBytes("ISO-8859-1"), "UTF-8");

大文件处理

java 复制代码
// 使用流式处理,避免全部加载到内存
try (InputStream stream = new FileInputStream("large.pdf")) {
    // 限制解析内容大小
    BodyContentHandler handler = new BodyContentHandler(1024 * 1024);
    parser.parse(stream, handler, metadata);
}

异常处理

java 复制代码
import org.apache.tika.exception.TikaException;
import org.xml.sax.SAXException;

try {
    String content = tika.parseToString(file);
} catch (TikaException e) {
    // Tika 特定错误(如无法解析)
    System.err.println("Tika error: " + e.getMessage());
} catch (IOException e) {
    // 文件读写错误
    System.err.println("IO error: " + e.getMessage());
} catch (SAXException e) {
    // XML 解析错误
    System.err.println("SAX error: " + e.getMessage());
}

10. 完整示例:文档索引工具

java 复制代码
import org.apache.tika.Tika;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DocumentIndexer {
    private static final Tika tika = new Tika();
    private static final AutoDetectParser parser = new AutoDetectParser();
    
    public static class DocumentInfo {
        String path;
        String content;
        String mimeType;
        String author;
        String title;
        long fileSize;
        
        @Override
        public String toString() {
            return String.format("File: %s\nType: %s\nAuthor: %s\nTitle: %s\nSize: %d bytes\nContent: %.100s...\n",
                path, mimeType, author, title, fileSize, content);
        }
    }
    
    public static DocumentInfo indexDocument(File file) throws Exception {
        DocumentInfo info = new DocumentInfo();
        info.path = file.getAbsolutePath();
        info.fileSize = file.length();
        info.mimeType = tika.detect(file);
        
        Metadata metadata = new Metadata();
        BodyContentHandler handler = new BodyContentHandler(1000000); // 1MB限制
        
        try (InputStream stream = new FileInputStream(file)) {
            parser.parse(stream, handler, metadata, new ParseContext());
            info.content = handler.toString();
            
            info.author = metadata.get("Author");
            if (info.author == null) info.author = metadata.get("creator");
            
            info.title = metadata.get("Title");
            if (info.title == null) info.title = file.getName();
        }
        
        return info;
    }
    
    public static void main(String[] args) throws Exception {
        File directory = new File("/path/to/documents");
        List<DocumentInfo> documents = new ArrayList<>();
        
        Files.walk(directory.toPath())
            .filter(Files::isRegularFile)
            .limit(100)
            .forEach(path -> {
                try {
                    documents.add(indexDocument(path.toFile()));
                } catch (Exception e) {
                    System.err.println("Failed to index: " + path + " - " + e.getMessage());
                }
            });
        
        // 输出结果
        documents.forEach(doc -> System.out.println(doc));
        
        // 全文搜索示例
        String searchTerm = "important";
        System.out.println("\nSearching for: " + searchTerm);
        documents.stream()
            .filter(doc -> doc.content.toLowerCase().contains(searchTerm.toLowerCase()))
            .forEach(doc -> System.out.println("Found in: " + doc.path));
    }
}

11. 版本升级说明

从 1.x 到 2.x 的主要变化:

  • Java 11+ 要求

  • API 包名从 org.apache.tika.parser 保持不变

  • 移除了部分过时 API

  • 性能优化和内存改进

相关推荐
luj_17681 小时前
FreeDOS vs MS-DOS PC-DOS 对比解析
服务器·c语言·开发语言·经验分享·算法
鹅城剑仙1 小时前
Java线程池完全指南
java
桀人1 小时前
C++——string类的详细介绍
开发语言·c++
李白的天不白1 小时前
SmartAdmin(基于 Spring Boot 框架)中配置跨域请求 VUE3 设置请求头
java·前端
橙子进阶之路1 小时前
Java线程(CompletableFuture)
java·开发语言
笨笨没好名字2 小时前
Leetcode刷题python版第一周
python·算法·leetcode
Cthy_hy2 小时前
斯特林数:组合划分的递归经典,一二两类全解
python·算法·斯特林数
鹅城剑仙2 小时前
Java CompletableFuture 异步编程完全指南
java
2601_961875242 小时前
法考备考计划表|学习计划|资料已整理
java·开发语言·学习·eclipse·tomcat·c#·hibernate