Abrufen des MIME-Typs einer Datei in Java


336

Ich habe mich nur gefragt, wie die meisten Leute einen MIME-Typ aus einer Datei in Java abrufen. Bisher habe ich zwei Utensilien ausprobiert: JMimeMagic& Mime-Util.

Das erste gab mir Speicherausnahmen, das zweite schließt seine Streams nicht richtig ab. Ich habe mich nur gefragt, ob jemand eine Methode / Bibliothek hat, die er verwendet und richtig funktioniert hat.


4
Eine gute Übersicht über die verfügbaren Bibliotheken finden Sie unter rgagnon.com/javadetails/java-0487.html
koppor

Ich habe die Klasse verwendet, die hier als Antwort gepostet wurde: stackoverflow.com/a/10140531/293280
Joshua Pinter

3
Tika sollte jetzt die Antwort sein. Die anderen Antworten unten beleuchten viele Abhängigkeiten mit Tika, aber ich sehe keine mit Tika-Core.
javamonkey79

@ javamonkey79 Wenn wir TIka verwenden, verdeckt es die Datei und ist nicht mehr verwendbar. Zeichenfolge contentType = tika.detect (is).
Cool Techie

Antworten:


326

In Java 7 können Sie jetzt einfach verwenden Files.probeContentType(path).


62
Beachten Sie, dass Files.probeContentType (Path) unter mehreren Betriebssystemen fehlerhaft ist und viele Fehlerberichte abgelegt wurden. Ich hatte ein Problem mit Software, die unter Ubuntu funktioniert, aber unter Windows fehlschlägt. Unter Windows schien Files.probeContentType (Path) immer null zurückzugeben. Es war nicht mein System, also habe ich weder die JRE- noch die Windows-Version überprüft. Es war Windows 7 oder 8 wahrscheinlich mit Orakel JRE für Java 7.
Silber

13
Ich laufe auf OS X 10.9 und ich nullAusschau nach .xml, .pngund .xhtmlDateien. Ich weiß nicht, ob ich nur etwas schrecklich Falsches mache, aber das scheint ziemlich schrecklich.

36
Eine wesentliche Einschränkung dabei ist, dass die Datei im Dateisystem vorhanden sein muss. Dies funktioniert nicht mit einem Stream oder einem Byte-Array usw.
Necreaux

3
Diese Methode kann keinen MIME-Typ zurückgeben, wenn ich die Erweiterung aus dem Namen entferne. Zum Beispiel, wenn der Name test.mp4 ist, ändere ich ihn in "test" und die Methode gibt null zurück. Außerdem ändere ich die Filmerweiterung in PNG usw. Sie gibt den PNG-MIME-Typ zurück
Sarkhan

10
Dies ist nutzlos, wenn die Datei eine fehlende oder falsche Erweiterung hat.
Shmosel

215

Unglücklicherweise,

mimeType = file.toURL().openConnection().getContentType();

funktioniert nicht, da diese Verwendung von URL eine Datei gesperrt lässt, so dass sie beispielsweise nicht löschbar ist.

Sie haben jedoch Folgendes:

mimeType= URLConnection.guessContentTypeFromName(file.getName());

und auch das Folgende, das den Vorteil hat, über die bloße Verwendung der Dateierweiterung hinauszugehen und einen Blick auf den Inhalt zu werfen

InputStream is = new BufferedInputStream(new FileInputStream(file));
mimeType = URLConnection.guessContentTypeFromStream(is);
 //...close stream

Wie aus dem obigen Kommentar hervorgeht, ist die integrierte Tabelle der MIME-Typen jedoch recht begrenzt, beispielsweise ohne MSWord und PDF. Wenn Sie also verallgemeinern möchten, müssen Sie über die integrierten Bibliotheken hinausgehen, z. B. Mime-Util (eine großartige Bibliothek, die sowohl die Dateierweiterung als auch den Inhalt verwendet).


8
Perfekte Lösung - hat mir sehr geholfen! Einwickeln FileInputStreamin BufferedInputStreamist entscheidender Teil - ansonsten guessContentTypeFromStreamkehrt null(bestanden InputStreamInstanz sollte Marken unterstützen)
Yuriy Nakonechnyy

11
Es gibt URLConnectionjedoch nur eine sehr begrenzte Anzahl von Inhaltstypen, die erkannt werden. Zum Beispiel kann es nicht erkennen application/pdf.
Kpentchev

3
Es bleibt nur verschlossen, weil Sie sich keine Möglichkeit gelassen haben, es zu schließen. Das Trennen der URLConnection würde sie entsperren.
Marquis von Lorne

1
Sowohl erratenContentTypeFromStream als auch erratenContentTypeFromName erkennen zB mp4
Hartmut P.

3
guessContentTypeFromName()verwendet die Standarddatei $JAVA_HOME/lib/content-types.properties. Sie können Ihre eigene erweiterte Datei hinzufügen, indem Sie die Systemeigenschaft ändernSystem.setProperty("content.types.user.table","/lib/path/to/your/property/file");
Rasika Perera

50

Die JAF-API ist Teil von JDK 6. Sehen Sie sich das javax.activationPaket an.

Die interessantesten Klassen sind javax.activation.MimeType- ein tatsächlicher MIME-Typinhaber - und javax.activation.MimetypesFileTypeMap- eine Klasse, deren Instanz den MIME-Typ als Zeichenfolge für eine Datei auflösen kann:

String fileName = "/path/to/file";
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();

// only by file name
String mimeType = mimeTypesMap.getContentType(fileName);

// or by actual File instance
File file = new File(fileName);
mimeType = mimeTypesMap.getContentType(file);

4
Leider als Javadoc für getContentType(File)Zustände: Gibt den MIME-Typ des Dateiobjekts zurück. Die Implementierung in dieser Klasse ruft auf getContentType(f.getName()).
Matyas

3
Und erinnern Sie sich diese Funktionalität mit META-INF erweitern kann / mime.types so dass es perfekt ist , wenn Sie gezwungen sind , Java 6. verwenden docs.oracle.com/javaee/5/api/javax/activation/...
Chexpir

7
Sie können das Erstellen eines neuen Objekts überspringen vonMimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(file)
akostadinov

Danke für deine Antwort. Es funktioniert erfolgreich für mich.
Radadiya Nikunj

Der Inhaltstyp wird jedoch nur basierend auf dem Dateinamen zurückgegeben. Dies ist besonders gefährlich für Dateien, die von Benutzern hochgeladen wurden.
Sergey Ponomarev

47

Mit Apache Tika benötigen Sie nur drei Codezeilen :

File file = new File("/path/to/file");
Tika tika = new Tika();
System.out.println(tika.detect(file));

Wenn Sie eine groovige Konsole haben, fügen Sie einfach diesen Code ein und führen Sie ihn aus, um damit zu spielen:

@Grab('org.apache.tika:tika-core:1.14')
import org.apache.tika.Tika;

def tika = new Tika()
def file = new File("/path/to/file")
println tika.detect(file)

Denken Sie daran, dass seine APIs reichhaltig sind und "alles" analysieren können. Ab Tika-Core 1.14 haben Sie:

String  detect(byte[] prefix)
String  detect(byte[] prefix, String name)
String  detect(File file)
String  detect(InputStream stream)
String  detect(InputStream stream, Metadata metadata)
String  detect(InputStream stream, String name)
String  detect(Path path)
String  detect(String name)
String  detect(URL url)

Weitere Informationen finden Sie in den Apidocs .


1
Es funktioniert nicht für CSV. wtf? stackoverflow.com/questions/46960231/…
gstackoverflow

1
Eine schlechte Sache an Tika ist, dass sich viele Abhängigkeiten aufblähen. Es hat die Größe meines Glases um 54 MB erhöht !!!
Helmy

1
@helmyTika 1.17 ist eigenständig und nur 648 KB groß.
Sainan

... oder nur new Tika().detect(file.toPath())zur Erkennung der Dateierweiterung und nicht zur Erkennung anhand des Inhalts der Datei
Lu55

@ Lu55-Dokumente sagen, dass der Dokumentinhalt weiterhin verwendet wird. Ich denke du meinst new Tika().detect(file.getPath()), die nur die Dateierweiterung verwendet
delucasvb

31

Apache Tika bietet im Tika-Core eine MIME-Typerkennung basierend auf magischen Markern im Stream-Präfix. tika-coreruft keine anderen Abhängigkeiten ab, wodurch es so leicht wie das derzeit nicht verwaltete Dienstprogramm zur Erkennung von MIME-Typen ist .

Einfaches Codebeispiel (Java 7) unter Verwendung der Variablen theInputStreamundtheFileName

try (InputStream is = theInputStream;
        BufferedInputStream bis = new BufferedInputStream(is);) {
    AutoDetectParser parser = new AutoDetectParser();
    Detector detector = parser.getDetector();
    Metadata md = new Metadata();
    md.add(Metadata.RESOURCE_NAME_KEY, theFileName);
    MediaType mediaType = detector.detect(bis, md);
    return mediaType.toString();
}

Bitte beachten Sie, dass MediaType.detect (...) nicht direkt verwendet werden kann ( TIKA-1120 ). Weitere Hinweise finden Sie unter https://tika.apache.org/0.10/detection.html .


1
+1 Metadata.RESOURCE_NAME_KEYKann auch weggelassen werden (wenn Sie keinen haben oder sich nicht auf den ursprünglichen Namen verlassen können), aber in diesem Fall erhalten Sie in einigen Fällen ein falsches Ergebnis (z. B. Bürodokumente).
Benutzer1516873

Es gibt einige Probleme beim Erkennen von XLSX, wenn der Dateiname keine Erweiterung enthält ... aber diese Lösung ist einfach und elegant.
Oscar Pérez

23

Wenn Sie ein Android-Entwickler sind, können Sie eine Dienstprogrammklasse verwenden, android.webkit.MimeTypeMapdie MIME-Typen Dateierweiterungen zuordnet und umgekehrt.

Das folgende Code-Snippet kann Ihnen helfen.

private static String getMimeType(String fileUrl) {
    String extension = MimeTypeMap.getFileExtensionFromUrl(fileUrl);
    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}

3
Dies funktioniert auch, wenn Sie es mit lokalen Dateipfaden wie "/sdcard/path/to/video.extension" versuchen. Das Problem ist, wenn die lokale Datei Speicherplatz in ihrem Pfad enthält, gibt sie immer null
nmxprime

17

Von Roseindia :

FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimeType = fileNameMap.getContentTypeFor("alert.gif");

7
Wer auch immer die Antwort abgelehnt hat, fügt bitte einen Kommentar hinzu, damit ich (und andere) lernen können, bessere Antworten zu veröffentlichen.
AlikElzin-Kilaka

3
Ich habe Sie nicht abgewählt, aber getFileNameMap funktioniert nicht für viele grundlegende Dateitypen, zum Beispiel 'bmp'. Auch URLConnection.guessContentTypeFromName gibt dasselbe zurück
Ovidiu Buligan

5
Sehr unvollständige Funktion. Ab Java 7 geben HTML-, PDF- und JPEG-Erweiterungen den richtigen MIME-Typ zurück, aber Js und CSS geben null zurück!
Djsumdog

Ich habe mit 'webm' getestet und es wurde null zurückgegeben.
Henrique Rocha

16

Wenn Sie mit Java 5-6 nicht weiterkommen, können Sie diese Dienstprogrammklasse aus dem Open Source-Produkt servoy verwenden .

Sie benötigen nur diese Funktion

public static String getContentType(byte[] data, String name)

Es prüft die ersten Bytes des Inhalts und gibt die Inhaltstypen basierend auf diesem Inhalt und nicht nach Dateierweiterung zurück.


Arbeitete für die einfachen, beliebten und wenigen Dateitypen, die ich brauchte :)
user489041

13

Ich habe mich nur gefragt, wie die meisten Leute einen MIME-Typ aus einer Datei in Java abrufen.

Ich habe mein SimpleMagic Java-Paket veröffentlicht, das die Bestimmung des Inhaltstyps ( MIME -Typ) aus Dateien und Byte-Arrays ermöglicht. Es dient zum Lesen und Ausführen der magischen Dateien für Unix-Dateien (1), die Teil der meisten ~ Unix-Betriebssystemkonfigurationen sind.

Ich habe Apache Tika ausprobiert, aber es ist riesig mit unzähligen Abhängigkeiten, URLConnectionverwendet nicht die Bytes der Dateien und betrachtet MimetypesFileTypeMapauch nur die Dateinamen.

Mit SimpleMagic können Sie Folgendes tun:

// create a magic utility using the internal magic file
ContentInfoUtil util = new ContentInfoUtil();
// if you want to use a different config file(s), you can load them by hand:
// ContentInfoUtil util = new ContentInfoUtil("/etc/magic");
...
ContentInfo info = util.findMatch("/tmp/upload.tmp");
// or
ContentInfo info = util.findMatch(inputStream);
// or
ContentInfo info = util.findMatch(contentByteArray);

// null if no match
if (info != null) {
   String mimeType = info.getMimeType();
}

1
Getestet auf mehreren Bilddateien. Alle hatten Erweiterung umbenannt. Ihre großartige Bibliothek hat es richtig gehandhabt. Natürlich auch sein Licht :).
Saurabheights

1
Ja, das funktioniert gut. Und für diejenigen, die diese Lösung in Android verwenden müssen, können Sie einfach Folgendes in die build.gradle-Datei aufnehmen: compile ('com.j256.simplemagic: simplemagic: 1.10')
jkincali

1
Dies ist eine großartige Lösung! Vielen Dank!
Javydreamercsw

5

Mit meinen 5 Cent einsteigen:

TL, DR

Ich benutze MimetypesFileTypeMap und füge jede , die nicht vorhanden ist und die ich speziell benötige, in die Datei mime.types ein.

Und jetzt die lange Lektüre:

Erstens ist die Liste der MIME-Typen riesig , siehe hier: https://www.iana.org/assignments/media-types/media-types.xhtml

Ich verwende gerne zuerst die von JDK bereitgestellten Standardeinrichtungen. Wenn dies nicht funktioniert, suche ich nach etwas anderem.

Bestimmen Sie den Dateityp anhand der Dateierweiterung

Seit 1.6 verfügt Java über MimetypesFileTypeMap, wie in einer der obigen Antworten angegeben, und es ist die einfachste Methode, den MIME-Typ zu bestimmen:

new MimetypesFileTypeMap().getContentType( fileName );

In seiner Vanilla-Implementierung macht dies nicht viel (dh es funktioniert für .html, aber nicht für .png). Es ist jedoch sehr einfach, einen beliebigen Inhaltstyp hinzuzufügen:

  1. Erstellen Sie eine Datei mit dem Namen 'mime.types' im Ordner META-INF in Ihrem Projekt
  2. Fügen Sie für jeden benötigten MIME-Typ eine Zeile hinzu, die von der Standardimplementierung nicht bereitgestellt wird (es gibt Hunderte von MIME-Typen, und die Liste wächst mit der Zeit).

Beispieleinträge für PNG- und JS-Dateien wären:

image/png png PNG
application/javascript js

Weitere Informationen zum Dateiformat mime.types finden Sie hier: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html

Bestimmen Sie den Dateityp anhand des Dateiinhalts

Java verfügt seit 1.7 über java.nio.file.spi.FileTypeDetector , das eine Standard-API zum Implementieren eines Dateityps auf implementierungsspezifische Weise definiert .

Um den MIME-Typ für eine Datei abzurufen, verwenden Sie einfach " Dateien" und tun dies in Ihrem Code:

Files.probeContentType(Paths.get("either file name or full path goes here"));

Die API-Definition bietet Funktionen, die entweder die Bestimmung des Dateimimetyps anhand des Dateinamens oder anhand des Dateiinhalts (magische Bytes) unterstützen. Deshalb ist probeContentType () -Methode eine IOException aus, falls eine Implementierung dieser API den bereitgestellten Pfad verwendet, um tatsächlich zu versuchen, die zugehörige Datei zu öffnen.

Auch hier lässt die Vanille- Implementierung (die mit JDK geliefert wird) zu wünschen übrig.

In einer idealen Welt in einer weit entfernten Galaxie würden all diese Bibliotheken, die versuchen, dieses Problem vom Typ Datei-zu-Pantomime zu lösen, einfach java.nio.file.spi.FileTypeDetector implementieren . Sie würden das Jar der bevorzugten implementierenden Bibliothek Datei in Ihren Klassenpfad und das wäre es.

In der realen Welt, in der Sie den Abschnitt TL, DR benötigen, sollten Sie die Bibliothek mit den meisten Sternen neben dem Namen finden und verwenden. Für diesen speziellen Fall brauche ich (noch;)) keinen.


3

Ich habe verschiedene Möglichkeiten ausprobiert, einschließlich der ersten, die von @Joshua Fox gesagt wurden. Einige erkennen jedoch keine häufigen Mimetypen wie bei PDF-Dateien, andere können bei gefälschten Dateien nicht vertrauenswürdig sein (ich habe es mit einer RAR-Datei versucht, deren Erweiterung in TIF geändert wurde). Die Lösung, die ich gefunden habe, wie auch von @Joshua Fox oberflächlich gesagt, ist die Verwendung von MimeUtil2 wie folgt :

MimeUtil2 mimeUtil = new MimeUtil2();
mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
String mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file)).toString();

5
Mit MimeUtil2 hatte ich überhaupt keinen Erfolg - fast alles kam als Anwendung / Oktett-Stream zurück. Ich habe MimeUtil.getMimeTypes () nach der Initialisierung mit `MimeUtil.registerMimeDetector (" eu.medsea.mimeutil.detector.MagicMimeMimeDetector ") mit viel mehr Erfolg verwendet. MimeUtil.registerMimeDetector ("eu.medsea.mimeutil.detector.ExtensionMimeDetector"); MimeUtil.registerMimeDetector ("eu.medsea.mimeutil.detector.OpendesktopMimeDetector"); `
Brian Pipa

2
Danke für die funktionierende Lösung. In der Dokumentation von mime-util ist nicht sehr klar, wie die Utility-Klasse instanziiert werden soll. Endlich zum Laufen gebracht, aber die Klassennamenzeichenfolge durch die eigentliche Klasse ersetzt. MimeUtil.registerMimeDetector (ExtensionMimeDetector.class.getName ()); String mimeType = MimeUtil.getMostSpecificMimeType (MimeUtil.getMimeTypes (Dateiname)). ToString ();
Rob Juurlink

2

Es ist besser, die Zwei-Ebenen-Validierung für das Hochladen von Dateien zu verwenden.

Zuerst können Sie nach dem mimeType suchen und ihn validieren.

Zweitens sollten Sie versuchen, die ersten 4 Bytes Ihrer Datei in hexadezimal zu konvertieren und sie dann mit den magischen Zahlen zu vergleichen. Dann ist es eine wirklich sichere Möglichkeit, nach Dateivalidierungen zu suchen.


2

Dies ist der einfachste Weg, den ich dafür gefunden habe:

byte[] byteArray = ...
InputStream is = new BufferedInputStream(new ByteArrayInputStream(byteArray));
String mimeType = URLConnection.guessContentTypeFromStream(is);

Beste Lösung!
Sherzod

2

Wenn Sie mit einem Servlet arbeiten und der Servlet-Kontext für Sie verfügbar ist, können Sie Folgendes verwenden:

getServletContext().getMimeType( fileName );

1
Was ist getServletContext?
e-info128

1

im Frühjahr MultipartFile- Datei;

org.springframework.web.multipart.MultipartFile

file.getContentType();


0

Wenn Sie unter Linux arbeiten, gibt es eine Befehlszeile file --mimetype:

String mimetype(file){

   //1. run cmd
   Object cmd=Runtime.getRuntime().exec("file --mime-type "+file);

   //2 get output of cmd , then 
    //3. parse mimetype
    if(output){return output.split(":")[1].trim(); }
    return "";
}

Dann

mimetype("/home/nyapp.war") //  'application/zip'

mimetype("/var/www/ggg/au.mp3") //  'audio/mp3'

2
Dies wird funktionieren, ist jedoch IMO eine schlechte Praxis, da es Ihren Code an ein bestimmtes Betriebssystem bindet und erfordert, dass das externe Dienstprogramm auf dem System vorhanden ist, auf dem es ausgeführt wird. Versteh mich nicht falsch; Es ist eine voll gültige Lösung, bricht aber die Portabilität - was einer der Hauptgründe ist, Java überhaupt zu verwenden ...
ToVine

@ ToVine: Für die Aufzeichnung werde ich respektvoll widersprechen. Nicht jedes Java-Programm muss portabel sein. Lassen Sie den Kontext und den Programmierer diese Entscheidung treffen. en.wikipedia.org/wiki/Java_Native_Interface
Zahnon

0

Nachdem ich verschiedene andere Bibliotheken ausprobiert hatte, entschied ich mich für mime-util.

<groupId>eu.medsea.mimeutil</groupId>
      <artifactId>mime-util</artifactId>
      <version>2.1.3</version>
</dependency>

File file = new File("D:/test.tif");
MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
Collection<?> mimeTypes = MimeUtil.getMimeTypes(file);
System.out.println(mimeTypes);

0
public String getFileContentType(String fileName) {
    String fileType = "Undetermined";
    final File file = new File(fileName);
    try
    {
        fileType = Files.probeContentType(file.toPath());
    }
    catch (IOException ioException)
    {
        System.out.println(
                "ERROR: Unable to determine file type for " + fileName
                        + " due to exception " + ioException);
    }
    return fileType;
}

Diese Methode Files.probeContentType (String) ist seit JDK Version 1.7 verfügbar und funktioniert sehr gut für mich.
Reza Rahimi

Danke, nur ich kann nicht verstehen, warum einige Benutzer ihre Stimme abgegeben haben)))
Vazgen Torosyan


0

Sie können dies mit nur einer Zeile tun: MimetypesFileTypeMap (). GetContentType (neue Datei ("filename.ext")) . Schauen Sie sich den vollständigen Testcode an (Java 7):

import java.io.File;
import javax.activation.MimetypesFileTypeMap;
public class MimeTest {
    public static void main(String a[]){
         System.out.println(new MimetypesFileTypeMap().getContentType(
           new File("/path/filename.txt")));
    }
}

Dieser Code erzeugt die folgende Ausgabe: text / plain


0
File file = new File(PropertiesReader.FILE_PATH);
MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
String mimeType = fileTypeMap.getContentType(file);
URLConnection uconnection = file.toURL().openConnection();
mimeType = uconnection.getContentType();

4
Während dieser Code die Frage lösen kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern.
Shree

0

Ich habe es mit folgendem Code gemacht.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MimeFileType {

    public static void main(String args[]){

        try{
            URL url = new URL ("https://www.url.com.pdf");

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setDoOutput(true);
            InputStream content = (InputStream)connection.getInputStream();
            connection.getHeaderField("Content-Type");

            System.out.println("Content-Type "+ connection.getHeaderField("Content-Type"));

            BufferedReader in = new BufferedReader (new InputStreamReader(content));

        }catch (Exception e){

        }
    }
}

0

Apache Tika.

<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-parsers -->
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-parsers</artifactId>
    <version>1.24</version>
</dependency>

und zwei Codezeilen.

Tika tika=new Tika();
tika.detect(inputStream);

Screenshot unten

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.