Comment récupérer le type MIME des fichiers ?

Contexte

Dans le cadre d’un projet, j’ai eu besoin de déterminer le type MIME des fichiers. Je suis parti à la recherche de solution pour résoudre ce point. J’ai trouvé la librairie Apache Tika mais des solutions existent dans le JDK.

Solution Apache Tika

La librairie Apache Tika est un outil pour analyser le contenu des fichiers (détection, extraction des métadonnées ou du contenu de texte structuré).

Pour cela, il suffit d’inclure la librairie suivante :

<dependency>
  <groupId>org.apache.tika</groupId>
  <artifactId>tika-core</artifactId>
  <version>1.25</version>
</dependency>

Ensuite, le code est très simple car la librairie propose une classe Facade Tika qui fournit un certain nombre de services dont celui qui nous intéresse.

import org.apache.tika.Tika;

String typeMime = new Tika().detect(new File("/emplacement/de/mon/fichier"));
System.out.println("Type Mime trouvé : " + typeMime);

Solution JDK

Depuis le JDK 7, il existe déjà une solution pour détecter le type MIME. En effet, la classe Files possède une méthode statique probeContentType

import java.nio.file.Files;

String typeMime = Files.probeContentType(Path.of("/emplacement/de/mon/fichier"));
System.out.println("Type Mime trouvé : " + typeMime);

Cela fonctionne très bien mais il possède malheureusement des limites.

L’implémentation existante se base sur la RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies. La détection est réalisée sur le nom du fichier.

avertissement Cela implique que le contenu du fichier n’est pas exploité. L’effet de bord est que cela fonctionne même si le fichier n’existe pas.

C’est à dire que le même fichier (même contenu) va produire des résultats différents en fonction du nom de ce dernier.

 - mon-fichier.xml     => application/xml
 - mon-fichier.xml.txt => text/plain
 - mon-fichier         => null

Amélioration de la solution JDK

Le JDK offre une classe abstraite java.nio.file.spi.FileTypeDetector qui permet d’enrichir le système de détection par défaut.

Donc nous pouvons implémenter un détecteur utilisant la librairie Apache Tika.

public class TikaFileTypeDetector extends FileTypeDetector {

	@Override
	public String probeContentType(Path path) throws IOException {
		return new Tika().detect(path);
	}

}

Le principe d’extension utilise le mécanisme de ServiceLoader afin que le JDK utilise notre classe. C’est à dire que nous allons créer un répertoire META-INF/services et y placer le fichier s’appelant le nom de l’interface java.nio.file.spi.FileTypeDetector contenant le nom de notre classe d’implémentation et le tour est joué.

Ainsi, notre code utilise seulement le JDK sans dépendance externe et nous bénéficions des avantages de détection de la librarie Apache Tika.

Solution existante

Le projet Apache Tika a prévu aussi cette mise en oeuvre et l’a fait pour nous. Pour l’utiliser, il suffit de choisir le module tika-java7.

<dependency>
  <groupId>org.apache.tika</groupId>
  <artifactId>tika-java7</artifactId>
  <version>1.25</version>
</dependency>

avertissement En important le module tika-java7, nous n’avons plus besoin d’importer le module tika-core

Le nom du module peut améner une confusion en suggérant que le module fonctionne uniquement avec un JDK 7. Et bien non, la signification -java7 indique simplement que la librairie implémente la classe abstraite FileTypeDetector ajoutée dans le JDK 7.

Compléments

Au niveau de la librairie Apache Tika, il est à noter une différence de traitement si nous passons en argument une instance de String ou une instance de File à la méhode detect

  • Si le paramètre est un String, cela implique une détection par le nom

  • Si le paramètre est un File, cela implique une détection par le contenu

Bonne détection !