【问题标题】:Getting MimeType subtype with Apache tika使用 Apache tika 获取 MimeType 子类型
【发布时间】: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。

【问题讨论】:

    标签: java mime-types detection apache-tika


    【解决方案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 版本的其他人来说,这应该可以解决问题:

    1. 使用ZipContainerDetector,因为您可能不再有ContainerAwareDetector
    2. 为检测器的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>
    

    【讨论】:

      猜你喜欢
      • 2014-01-15
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      • 2012-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多