Получение подтипа MimeType с помощью Apache tika

мне нужно получить iana.org MediaType, а не application/zip или application/x-tika-msoffice для таких документов, как odt, ppt, pptx, xlsx и т. д.

Если вы посмотрите на типы.xml существуют элементы mimeType, состоящие из iana.org mime-тип и "подкласс-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 вместо имени родительского типа ?

при тестировании обнаружения типа 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, но application/zip для документов xlsx, docx, pptx.

4 ответов


первоначально TIKA поддерживала обнаружение только MIME Magic или расширением файла (glob), так как это все большинство обнаружения mime до Tika.

из-за проблем с MIME Magic и globs, когда дело доходит до обнаружения форматов контейнеров, было решено добавить некоторые новые детекторы в Tika для их обработки. Детекторы, распознающие контейнер, взяли весь файл, открыли и обработали контейнер, а затем разработали точный тип файла на основе содержимого. Первоначально, вам нужно чтобы вызвать их явно, но тогда они были завернуты в ContainerAwareDetector что вы увидите в некоторых из ответов.

С тех пор Tika добавила шаблон загрузчика услуг, первоначально для синтаксических анализаторов. Это позволило автоматически загружать классы, когда они присутствуют, с общим способом определить, какие из них были подходящими и использовать их. Затем эта поддержка была распространена и на детекторы, и в этот момент старый ContainerAwareDetector может быть удалена в пользу чего-то более чистого.

если вы на Тика 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);

если вы запустите это только с ядром TIKA jar (TIKA-core-1.2 -....), тогда единственным детектором будет MIME magics one, и вы получите обнаружение старого стиля, основанное только на magic + glob. Однако, если вы запустите это как с ядром, так и с парсером TIKA jars (плюс их зависимости) или из приложения Tika (которое включает core + parsers + dependencies автоматически), то DefaultDetector будет использовать все различные детекторы контейнеров для обработки файла. Если ваш файл основан на zip, то обнаружение будет включать обработку структуры zip для идентификации типа файла на основе того, что там. Это даст вам высокую точность обнаружения вы после, без необходимости вызывать много различных парсеров в свою очередь. DefaultDetector будет использовать все детекторы, которые доступны.


для тех, кто имеет аналогичную проблему, но использует более новую версию Tika, это должно сделать трюк:

  1. использовать ZipContainerDetector так как у вас может не быть ContainerAwareDetector больше.
  2. дать TikaInputStream до detect() метод детектора для обеспечения тика может проанализировать правильный тип мим.

мой пример кода выглядит так:

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 класс является частью моей модели домена. Так что у вас наверняка будет что-то похожее на эта линия.

Я надеюсь, что кто-то может использовать это.


правила обнаружения шаблонов байтов по умолчанию в TIKA-core могут определять только общий формат OLE2 или ZIP, используемый всеми типами документов MS Office. Вы хотите использовать 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;
}

таким образом, ваши тесты должны пройти


Вы можете использовать пользовательский файл конфигурации тика:

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>