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. 常见文件格式支持
| 格式 | 扩展名 | 支持程度 |
|---|---|---|
| 完整 | ||
| 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
-
性能优化和内存改进