使用 Apache tika 获取 MimeType 子类型
Posted
技术标签:
【中文标题】使用 Apache tika 获取 MimeType 子类型【英文标题】:Getting MimeType subtype with Apache tika 【发布时间】:2011-10-31 13:05:41 【问题描述】:对于 odt、ppt、pptx、xlsx 等文档,我需要获取 iana.org MediaType 而不是 application/zip 或 application/x-tika-msoffice。
如果您查看 mimetypes.xml,就会发现 mimeType 元素由 iana.org mime-type 和“sub-class-of”组成
<mime-type type="application/msword">
<alias type="application/vnd.ms-word"/>
............................
<glob pattern="*.doc"/>
<glob pattern="*.dot"/>
<sub-class-of type="application/x-tika-msoffice"/>
</mime-type>
如何获取 iana.org mime-type 名称而不是父类型名称?
在测试 mime 类型检测时,我会这样做:
MediaType mediaType = MediaType.parse(tika.detect(inputStream));
String mimeType = mediaType.getSubtype();
测试结果:
FAILED: getsCorrectContentType("application/vnd.ms-excel", docs/xls/en.xls)
java.lang.AssertionError: expected:<application/vnd.ms-excel> but was:<x-tika-msoffice>
FAILED: getsCorrectContentType("vnd.openxmlformats-officedocument.spreadsheetml.sheet", docs/xlsx/en.xlsx)
java.lang.AssertionError: expected:<vnd.openxmlformats-officedocument.spreadsheetml.sheet> but was:<zip>
FAILED: getsCorrectContentType("application/msword", doc/en.doc)
java.lang.AssertionError: expected:<application/msword> but was:<x-tika-msoffice>
FAILED: getsCorrectContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document", docs/docx/en.docx)
java.lang.AssertionError: expected:<application/vnd.openxmlformats-officedocument.wordprocessingml.document> but was:<zip>
FAILED: getsCorrectContentType("vnd.ms-powerpoint", docs/ppt/en.ppt)
java.lang.AssertionError: expected:<vnd.ms-powerpoint> but was:<x-tika-msoffice>
有没有办法从 mimetypes.xml 获取实际的子类型?而不是 x-tika-msoffice 或 application/zip ?
此外,我从来没有得到 application/x-tika-ooxml,而是 xlsx、docx、pptx 文档的 application/zip。
【问题讨论】:
【参考方案1】:最初,Tika 仅支持通过 Mime Magic 或文件扩展名 (glob) 进行检测,因为这是 Tika 之前的所有大多数 mime 检测。
由于在检测容器格式时 Mime Magic 和 glob 存在问题,因此决定在 Tika 中添加一些新的检测器来处理这些问题。 Container Aware Detectors 获取整个文件,打开并处理容器,然后根据内容计算出确切的文件类型。最初,您需要显式调用它们,但随后它们被包裹在 ContainerAwareDetector
中,您将在一些答案中看到。
从那时起,Tika 添加了一个服务加载器模式,最初是针对 Parsers 的。这允许类在存在时自动加载,并以一种通用的方式来识别哪些是合适的并使用它们。这种支持随后也扩展到了检测器,此时可以删除旧的 ContainerAwareDetector
以支持更清洁的东西。
如果您使用的是 Tika 1.2 或更高版本,并且想要准确检测所有格式,包括容器格式,您需要执行以下操作:
TikaConfig config = TikaConfig.getDefaultConfig();
Detector detector = config.getDetector();
TikaInputStream stream = TikaInputStream.get(fileOrStream);
Metadata metadata = new Metadata();
metadata.add(Metadata.RESOURCE_NAME_KEY, filenameWithExtension);
MediaType mediaType = detector.detect(stream, metadata);
如果您仅使用 Core Tika jar (tika-core-1.2-....) 运行此程序,那么唯一存在的检测器将是 mime 魔法检测器,您将获得基于魔法的旧式检测+ 仅限全局。但是,如果您同时使用 Core 和 Parser Tika jars(加上它们的依赖项),或者从 Tika App(自动包括核心 + 解析器 + 依赖项)运行它,那么 DefaultDetector 将使用所有各种不同的容器检测器来处理您的文件.如果您的文件是基于 zip 的,则检测将包括处理 zip 结构以根据其中的内容识别文件类型。这将为您提供所需的高精度检测,而无需依次调用许多不同的解析器。 DefaultDetector
将使用所有可用的检测器。
【讨论】:
如何使用 tika-app1.8 检测 .properties 文件。它将它检测为文本/纯文本,而不是我希望它作为文本/属性。我该如何自定义? @kittu 您需要将其作为一个新问题提出和/或在 Tika 问题跟踪器中提出增强请求 解析器 jar 需要哪些依赖项?它们是在一个单独的罐子里吗? 关键是将 tika 解析包含在依赖项中(连同核心),然后您可以简单地使用 Tika.detect(tikaInputStream) 就可以完成这项工作。无需元数据、媒体类型或提取检测器。【参考方案2】:对于遇到类似问题但使用较新 Tika 版本的其他人来说,这应该可以解决问题:
-
使用
ZipContainerDetector
,因为您可能不再有ContainerAwareDetector
。
为检测器的detect()
方法提供TikaInputStream
,以确保tika 可以分析正确的mime 类型。
我的示例代码如下所示:
public static String getMimeType(final Document p_document)
try
Metadata metadata = new Metadata();
metadata.add(Metadata.RESOURCE_NAME_KEY, p_document.getDocName());
Detector detector = getDefaultDectector();
LogMF.debug(log, "Trying to detect mime type with detector 0.", detector);
TikaInputStream inputStream = TikaInputStream.get(p_document.getData(), metadata);
return detector.detect(inputStream, metadata).toString();
catch (Throwable t)
log.error("Error while determining mime-type of " + p_document);
return null;
private static Detector getDefaultDectector()
if (detector == null)
List<Detector> detectors = new ArrayList<>();
// zip compressed container types
detectors.add(new ZipContainerDetector());
// Microsoft stuff
detectors.add(new POIFSContainerDetector());
// mime magic detection as fallback
detectors.add(MimeTypes.getDefaultMimeTypes());
detector = new CompositeDetector(detectors);
return detector;
请注意,Document
类是我的域模型的一部分。所以你肯定会在那一行有类似的东西。
我希望有人可以使用它。
【讨论】:
您最好只使用 DefaultDetector,而不是尝试自己调用单个检测器 我无法使用默认检测器检测到 word 2010 文档的 mime 类型。使用我的方法我可以。但我还没有针对其他文档类型对其进行过测试。 DefaultDetector 应该可以解决这个问题(有大量单元测试表明这一点!)。确保你的类路径中有 Tika Parsers jar,以及依赖项(如果没有) 我希望没有人使用捕获Throwable
并返回null
的代码。【参考方案3】:
tika-core 中的默认字节模式检测规则只能检测所有 MS Office 文档类型使用的通用 OLE2 或 ZIP 格式。您想使用 ContainerAwareDetector 进行这种检测 afaik。并使用 MimeTypes 检测器作为其后备检测器。试试这个:
public MediaType getContentType(InputStream is, String fileName)
MediaType mediaType;
Metadata md = new Metadata();
md.set(Metadata.RESOURCE_NAME_KEY, fileName);
Detector detector = new ContainerAwareDetector(tikaConfig.getMimeRepository());
try
mediaType = detector.detect(is, md);
catch (IOException ioe)
whatever;
return mediaType;
这样你的测试应该可以通过
【讨论】:
ContainerAwareDetector 在 Tika 中已经被弃用了一段时间,对于今天看到这个的人来说,你应该使用 Tika's new-ish DefaultDetector 以及类路径中的所有 tika 解析器【参考方案4】:您可以使用自定义 tika 配置文件:
MimeTypes mimes=MimeTypesFactory.create(Thread.currentThread()
.getContextClassLoader().getResource("tika-custom-MimeTypes.xml"));
Metadata metadata = new Metadata();
metadata.add(Metadata.RESOURCE_NAME_KEY, file.getName());
tis = TikaInputStream.get(file);
String mimetype = new DefaultDetector(mimes).detect(tis,metadata).toString();
在 WEB-INF/classes 中将“tika-custom-MimeTypes.xml”与您的更改放在一起:
就我而言:
<mime-type type="video/mp4">
<magic priority="60">
<match value="ftypmp41" type="string" offset="4"/>
<match value="ftypmp42" type="string" offset="4"/>
<!-- add -->
<match value="ftyp" type="string" offset="4"/>
</magic>
<glob pattern="*.mp4"/>
<glob pattern="*.mp4v"/>
<glob pattern="*.mpg4"/>
<!-- sub-class-of type="video/quicktime" /-->
</mime-type>
<mime-type type="video/quicktime">
<magic priority="50">
<match value="moov" type="string" offset="4"/>
<match value="mdat" type="string" offset="4"/>
<!--remove for videos of screencast -->
<!--match value="ftyp" type="string" offset="4"/-->
</magic>
<glob pattern="*.qt"/>
<glob pattern="*.mov"/>
</mime-type>
【讨论】:
以上是关于使用 Apache tika 获取 MimeType 子类型的主要内容,如果未能解决你的问题,请参考以下文章