使用Apache tika获取MimeType子类型

时间:2011-08-21 10:14:42

标签: java mime-types detection apache-tika

我需要获取iana.org MediaType而不是application / zip或application / x-tika-msoffice,用于odt,ppt,pptx,xlsx等文件。

如果你看一下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文档的应用程序/ zip。

4 个答案:

答案 0 :(得分:23)

最初,Tika只支持Mime Magic或文件扩展名(glob)的检测,因为这是Tika之前的大多数mime检测。

由于Mime Magic和Globs在检测容器格式方面存在问题,因此决定在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 magics,你会得到基于魔法的旧式探测器+仅限+ glob。但是,如果您使用Core和Parser Tika jar(以及它们的依赖项)或者Tika App(其中包括核心+解析器+依赖项)自动运行它,那么DefaultDetector将使用所有各种不同的容器检测器来处理您的文件。如果您的文件是基于zip的,那么检测将包括处理zip结构以根据其中的内容识别文件类型。这将为您提供高精度检测,而无需依次调用大量不同的解析器。 DefaultDetector将使用所有可用的探测器。

答案 1 :(得分:5)

对于其他有类似问题但使用较新的Tika版本的人来说,这应该可以解决问题:

  1. 使用ZipContainerDetector,因为您可能不再有ContainerAwareDetector
  2. 向检测器的TikaInputStream方法提供detect(),以确保tika可以分析正确的mime类型。
  3. 我的示例代码如下所示:

    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类是我的域模型的一部分。所以你肯定会在那条线上有类似的东西。

    我希望有人可以使用它。

答案 2 :(得分:2)

tika-core中的默认字节模式检测规则只能检测所有MS Office文档类型使用的通用OLE2或ZIP格式。您希望使用ContainerAwareDetector进行此类检测。并使用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;
}

这样你的测试应该通过

答案 3 :(得分:2)

您可以使用自定义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>