Apache Tika 是一个内容分析工具包,用于检测和提取文档中的元数据和文本内容。它支持超过1000种文件格式。
1. 核心特性
格式检测:自动识别文件类型(MIME)
内容提取:提取纯文本内容
元数据提取:获取作者、创建日期等信息
语言检测:识别文档语言
2. 快速开始
Maven 依赖
<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>基础用法
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(推荐新手)
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(更精细控制)
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(递归嵌入文件)
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. 配置选项
设置最大字符串长度
// 默认100k字符 BodyContentHandler handler = new BodyContentHandler(500000);自定义配置
import org.apache.tika.config.TikaConfig; TikaConfig config = new TikaConfig(); Tika tika = new Tika(config); // 或使用自定义配置文件 TikaConfig config = new TikaConfig("my-tika-config.xml");排除特定解析器
Parsers parsers = new Parsers(); Set<MediaType> excluded = Set.of( MediaType.APPLICATION_ZIP, MediaType.APPLICATION_PDF ); AutoDetectParser parser = new AutoDetectParser( parsers.getParsers(excluded) );6. 高级功能
语言检测
import org.apache.tika.language.LanguageIdentifier; String text = "This is an English sentence."; LanguageIdentifier identifier = new LanguageIdentifier(text); String language = identifier.getLanguage(); // "en"提取特定元数据
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);嵌入式内容处理
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 提供了命令行版本:
# 下载 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.pdf8. 性能优化
复用解析器实例
// 正确做法 - 单例 private static final AutoDetectParser PARSER = new AutoDetectParser(); // 错误做法 - 每次新建 // AutoDetectParser parser = new AutoDetectParser(); // 消耗资源使用ParseContext缓存
ParseContext context = new ParseContext(); context.set(Parser.class, PARSER); // 复用context parser.parse(stream, handler, metadata, context);配置内存限制
TikaConfig config = TikaConfig.getDefaultConfig(); // 修改配置限制解析时间和内存9. 常见问题解决
中文乱码
// 确保使用正确的字符编码 BodyContentHandler handler = new BodyContentHandler(-1); // 手动设置编码 String content = new String(text.getBytes("ISO-8859-1"), "UTF-8");大文件处理
// 使用流式处理,避免全部加载到内存 try (InputStream stream = new FileInputStream("large.pdf")) { // 限制解析内容大小 BodyContentHandler handler = new BodyContentHandler(1024 * 1024); parser.parse(stream, handler, metadata); }异常处理
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. 完整示例:文档索引工具
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
性能优化和内存改进