Apache Tika 2.4.1添加自定义Detector的正确方法及异常解决
Apache Tika 2.4.1 自定义SVG检测器的正确实现方法
问题根源
你直接通过new Tika(new SvgDetector())初始化Tika实例时,会替换掉默认的所有检测器集合,只保留自定义的SVG检测器。当检测非SVG文件(如.png)时,自定义检测器返回null,后续调用toString()就会触发空指针异常。
正确实现方案
方案1:组合自定义检测器与默认检测器集合
将自定义SVG检测器添加到Tika默认的检测器列表中,这样既保留原有检测能力,又能识别SVG文件:
import org.apache.tika.Tika; import org.apache.tika.detect.CompositeDetector; import org.apache.tika.detect.Detector; import org.apache.tika.config.TikaConfig; import java.util.ArrayList; import java.util.List; // 获取Tika默认的检测器集合 Detector defaultDetector = TikaConfig.getDefaultConfig().getDetector(); // 组合自定义检测器与默认检测器 List<Detector> detectors = new ArrayList<>(); detectors.add(new SvgDetector()); detectors.add(defaultDetector); CompositeDetector compositeDetector = new CompositeDetector(detectors); // 使用组合后的检测器创建Tika实例 Tika tika = new Tika(compositeDetector); String mimeTypeValue = tika.detect(multipartFile.getInputStream());
优化自定义SvgDetector的实现
原检测器存在两个问题:一是读取整个输入流会导致流耗尽,影响后续处理;二是检测逻辑过于严格(要求首尾严格匹配<svg>和</svg>),容易误判。优化后的实现如下:
import org.apache.tika.detect.Detector; import org.apache.tika.io.MarkableInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; public class SvgDetector implements Detector { private static final MediaType SVG_TYPE = MediaType.parse("image/svg+xml"); // 仅读取文件前1024个字符做检测,避免耗尽流 private static final int MAX_READ_LENGTH = 1024; @Override public MediaType detect(InputStream input, Metadata metadata) throws IOException { MarkableInputStream markableInput = new MarkableInputStream(input); try { // 标记当前流位置,后续可重置 markableInput.mark(MAX_READ_LENGTH); byte[] buffer = new byte[MAX_READ_LENGTH]; int actualRead = markableInput.read(buffer); String contentPrefix = new String(buffer, 0, actualRead, StandardCharsets.UTF_8).toLowerCase(); // 宽松检测SVG标签(兼容带命名空间的情况,如<svg xmlns="http://www.w3.org/2000/svg">) if (contentPrefix.contains("<svg")) { return SVG_TYPE; } return null; } finally { // 重置流位置,确保后续检测器能正常读取 markableInput.reset(); } } }
方案2:在自定义检测器中委托默认检测
如果不想手动组合检测器,也可以在自定义检测器中先尝试SVG检测,未命中时委托给默认检测器:
import org.apache.tika.detect.Detector; import org.apache.tika.io.MarkableInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import org.apache.tika.config.TikaConfig; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; public class SvgDetector implements Detector { private final Detector defaultDetector = TikaConfig.getDefaultConfig().getDetector(); private static final MediaType SVG_TYPE = MediaType.parse("image/svg+xml"); private static final int MAX_READ_LENGTH = 1024; @Override public MediaType detect(InputStream input, Metadata metadata) throws IOException { MarkableInputStream markableInput = new MarkableInputStream(input); try { markableInput.mark(MAX_READ_LENGTH); byte[] buffer = new byte[MAX_READ_LENGTH]; int actualRead = markableInput.read(buffer); String contentPrefix = new String(buffer, 0, actualRead, StandardCharsets.UTF_8).toLowerCase(); if (contentPrefix.contains("<svg")) { return SVG_TYPE; } // 未命中SVG,委托给默认检测器 markableInput.reset(); return defaultDetector.detect(markableInput, metadata); } finally { markableInput.reset(); } } }
此时直接使用new Tika(new SvgDetector())初始化即可,无需额外组合检测器。
内容的提问来源于stack exchange,提问作者SageJustus
相关产品推荐
相关产品推荐

