Ottenere il tipo Mime di un file in Java


336

Mi stavo solo chiedendo come la maggior parte delle persone recuperi un tipo MIME da un file in Java? Finora ho provato due programmi di utilità: JMimeMagic& Mime-Util.

Il primo mi ha dato eccezioni di memoria, il secondo non chiude correttamente i suoi flussi. Mi stavo solo chiedendo se qualcun altro avesse un metodo / libreria che hanno usato e funzionato correttamente?


4
Una buona panoramica delle librerie disponibili è disponibile su rgagnon.com/javadetails/java-0487.html
koppor

Ho usato la classe che è stata pubblicata come risposta qui: stackoverflow.com/a/10140531/293280
Joshua Pinter

3
Tika dovrebbe essere la risposta ora. Le altre risposte di seguito evidenziano molte dipendenze con Tika, ma non ne vedo nessuna con tika-core.
javamonkey79,

@ javamonkey79 quando usiamo TIka, copre il file e non è più utilizzabile. String contentType = tika.detect (is).
Fantastico Techie il

Risposte:


326

In Java 7 ora puoi semplicemente usare Files.probeContentType(path).


62
Tieni presente che Files.probeContentType (Path) è difettoso su diversi sistemi operativi e sono stati archiviati molti rapporti di bug. Ho avuto un problema con il software che funzionava su Ubuntu ma non funzionava su Windows. Sembrava che su Windows Files.probeContentType (Path) restituisse sempre null. Non era il mio sistema, quindi non ho verificato la versione di JRE o Windows. Era Windows 7 o 8 probabilmente con Oracle JRE per Java 7.
Silver

13
Sono in esecuzione su OS X 10.9 e ottengo nullfuori per .xml, .pnge .xhtmlfile. Non so se sto facendo qualcosa di orribilmente sbagliato, ma sembra piuttosto terribile.

36
Una grande limitazione è che il file deve esistere nel file system. Questo non funziona con un flusso o un array di byte, ecc.
Necreaux

3
questo metodo non può restituire il tipo mime quando rimuovo l'estensione dal nome. Per esempio se il nome è test.mp4 lo cambio in "test" e il metodo restituisce null. Inoltre cambio l'estensione del film in png ecc. restituisce il tipo mime png
Sarkhan

10
Questo è inutile se il file ha un'estensione mancante o errata.
shmosel,

215

Sfortunatamente,

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

non funziona, poiché questo utilizzo dell'URL lascia un file bloccato, in modo che, ad esempio, non sia cancellabile.

Tuttavia, hai questo:

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

e anche quanto segue, che ha il vantaggio di andare oltre il semplice uso dell'estensione del file e dà una sbirciatina al contenuto

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

Tuttavia, come suggerito dal commento sopra, la tabella integrata dei tipi mime è piuttosto limitata, ad esempio MSWord e PDF. Quindi, se vuoi generalizzare, dovrai andare oltre le librerie integrate, usando, ad esempio, Mime-Util (che è una grande libreria, che utilizza sia l'estensione che il contenuto).


8
Soluzione perfetta - mi ha aiutato molto! Avvolgendo FileInputStreamin BufferedInputStreamè fondamentale parte - altrimenti guessContentTypeFromStreamrendimenti null(passati InputStreamesempio dovrebbe sostenere marchi)
Yuriy Nakonechnyy

11
Howerver, URLConnectionha un set molto limitato di tipi di contenuto che riconosce. Ad esempio, non è in grado di rilevare application/pdf.
kpentchev,

3
Lo lascia solo bloccato perché non ti sei lasciato modo di chiuderlo. Disconnessione di URLConnection per sbloccarlo.
Marchese di Lorne,

1
sia indovinareContentTypeFromStream né indovinareContentTypeFromName NON riconoscono ad esempio mp4
Hartmut P.

3
guessContentTypeFromName()utilizza il $JAVA_HOME/lib/content-types.propertiesfile predefinito . puoi aggiungere il tuo file esteso modificando la proprietà di sistemaSystem.setProperty("content.types.user.table","/lib/path/to/your/property/file");
Rasika Perera il

50

L'API JAF fa parte di JDK 6. Guarda il javax.activationpacchetto.

Le classi più interessanti sono javax.activation.MimeType- un vero detentore del tipo MIME - e javax.activation.MimetypesFileTypeMap- la cui istanza può risolvere il tipo MIME come String per un file:

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
Sfortunatamente, come javadoc for getContentType(File)afferma: Restituisce il tipo MIME dell'oggetto file. L'implementazione in questa classe chiama getContentType(f.getName()).
Matyas,

3
E ricorda che puoi estendere questa funzionalità con il file META-INF / mime.types, quindi è perfetto se sei costretto ad usare Java 6. docs.oracle.com/javaee/5/api/javax/activation/…
Chexpir

8
puoi saltare la creazione di un nuovo oggetto diMimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(file)
akostadinov il

Grazie per la tua risposta. Funziona con successo per me.
Radadiya Nikunj,

Ma restituisce comunque il tipo di contenuto solo in base al nome file. E questo è particolarmente pericoloso per i file caricati dagli utenti.
Sergey Ponomarev,

47

Con Apache Tika sono necessarie solo tre righe di codice :

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

Se hai una console groovy, incolla ed esegui questo codice per giocarci:

@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)

Tieni presente che le sue API sono ricche, può analizzare "qualsiasi cosa". A partire da tika-core 1.14, hai:

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)

Vedi gli apidocs per maggiori informazioni.



1
Una cosa negativa di Tika, un sacco di dipendenza gonfia. Ha aumentato le dimensioni del mio vaso di 54 MB !!!
helmy,

1
@helmyTika 1.17 è autonomo e grande solo 648 KB.
Sainan,

... o solo new Tika().detect(file.toPath())per il rilevamento basato sull'estensione del file piuttosto che per il rilevamento basato sul contenuto del file
Lu55

I documenti di @ Lu55 dicono che utilizza ancora il contenuto del documento. Penso che intendi new Tika().detect(file.getPath()), che utilizza solo l'estensione del file
delucasvb

31

Apache Tika offre in tika-core un rilevamento del tipo mime basato su marcatori magici nel prefisso dello stream. tika-corenon recupera altre dipendenze, il che la rende leggera come l' utilità di rilevamento del tipo Mime attualmente non mantenuta .

Esempio di codice semplice (Java 7), usando le variabili theInputStreametheFileName

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();
}

Si noti che MediaType.detect (...) non può essere utilizzato direttamente ( TIKA-1120 ). Ulteriori suggerimenti sono disponibili su https://tika.apache.org/0.10/detection.html .


1
+1 Inoltre Metadata.RESOURCE_NAME_KEYpuò essere omesso (se non ne hai o non puoi fare affidamento sul nome originale), ma in tal caso otterrai risultati errati in alcuni casi (documenti di Office ad esempio).
user1516873,

Ha alcuni problemi nel rilevare XLSX se non c'è estensione sul nome file ... ma questa soluzione è semplice ed elegante.
Oscar Pérez,

23

Se sei uno sviluppatore Android, puoi utilizzare una classe di utilità android.webkit.MimeTypeMapche associa i tipi MIME alle estensioni dei file e viceversa.

Il seguente frammento di codice può aiutarti.

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

3
Funziona anche se provato con percorsi di file locali come "/sdcard/path/to/video.extension". Il problema è che se il file locale contiene spazio nel suo percorso, restituisce sempre null
nmxprime

17

Da roseindia :

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

7
Chiunque abbia votato in negativo la risposta, si prega di aggiungere un commento in modo che io (e altri) possa imparare a pubblicare risposte migliori.
AlikElzin-Kilaka,

3
Non ti ho votato, ma getFileNameMap non funziona per molti tipi di file di base, ad esempio "bmp". Anche URLConnection.guessContentTypeFromName restituisce la stessa cosa
Ovidiu Buligan,

5
Funzione molto incompleta. A partire da Java 7, le estensioni html, pdf e jpeg restituiscono il tipo mime corretto ma js e css restituiscono null!
djsumdog,

Ho provato con 'webm' e ha restituito null.
Henrique Rocha,

16

Se sei bloccato con java 5-6, questa classe di utilità dal prodotto open source servoy .

Hai solo bisogno di questa funzione

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

Rileva i primi byte del contenuto e restituisce i tipi di contenuto in base a quel contenuto e non in base all'estensione del file.


Ha funzionato per i tipi di file semplici, popolari e di cui avevo bisogno :)
user489041

13

Mi stavo solo chiedendo come la maggior parte delle persone recuperi un tipo MIME da un file in Java?

Ho pubblicato il mio pacchetto Java SimpleMagic che consente la determinazione del tipo di contenuto (tipo mime) da file e array di byte. È progettato per leggere ed eseguire i file magici di comando file Unix (1) che fanno parte della maggior parte delle configurazioni del sistema operativo ~ Unix.

Ho provato Apache Tika ma è enorme con tonnellate di dipendenze, URLConnectionnon usa i byte dei file e MimetypesFileTypeMapguarda solo i nomi dei file.

Con SimpleMagic puoi fare qualcosa del tipo:

// 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
Testato su più file di immagine. Tutti avevano l'estensione rinominata. La tua fantastica libreria l'ha gestita correttamente. Naturalmente anche la sua luce :).
saurabheights,

1
Sì, funziona bene. E per coloro che necessitano di utilizzare questa soluzione all'interno di Android, puoi semplicemente includere quanto segue nel file build.gradle: compilare ('com.j256.simplemagic: simplemagic: 1.10')
jkincali

1
Questa è un'ottima soluzione! Grazie!
javydreamercsw,

5

Per entrare con i miei 5 centesimi:

TL, DR

Uso MimetypesFileTypeMap e aggiungo qualsiasi mime che non c'è e ne ho specificamente bisogno, nel file mime.types.

E ora, la lunga lettura:

Prima di tutto, l'elenco dei tipi MIME è enorme , vedi qui: https://www.iana.org/assignments/media-types/media-types.xhtml

Mi piace usare prima i servizi standard forniti da JDK e, se non funziona, andrò a cercare qualcos'altro.

Determina il tipo di file dall'estensione del file

Dalla 1.6, Java ha MimetypesFileTypeMap, come indicato in una delle risposte sopra, ed è il modo più semplice per determinare il tipo mime:

new MimetypesFileTypeMap().getContentType( fileName );

Nella sua implementazione alla vaniglia questo non fa molto (cioè funziona per .html ma non per .png). Tuttavia, è super semplice aggiungere qualsiasi tipo di contenuto di cui potresti aver bisogno:

  1. Crea il file "mime.types" nella cartella META-INF nel tuo progetto
  2. Aggiungi una riga per ogni tipo di mime di cui hai bisogno e l'implementazione predefinita non fornisce (ci sono centinaia di tipi di mime e la lista cresce con il passare del tempo).

Le voci di esempio per i file png e js sarebbero:

image/png png PNG
application/javascript js

Per il formato file mime.types, vedi maggiori dettagli qui: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html

Determina il tipo di file dal contenuto del file

Dall'1.7, Java ha java.nio.file.spi.FileTypeDetector , che definisce un'API standard per determinare un tipo di file in modo specifico per l'implementazione .

Per recuperare il tipo mime per un file, devi semplicemente usare File e farlo nel tuo codice:

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

La definizione dell'API fornisce funzionalità che supportano la determinazione del tipo di file mime dal nome del file o dal contenuto del file (byte magici). Questo è il motivo per cui il metodo probeContentType () genera IOException, nel caso in cui un'implementazione di questa API utilizzi il percorso fornito ad essa per provare effettivamente ad aprire il file ad esso associato.

Ancora una volta, l' implementazione vaniglia di questo (quello che viene fornito con JDK) lascia molto a desiderare.

In un mondo ideale in una galassia molto, molto lontano, tutte queste librerie che provano a risolvere questo problema di tipo file-to-mime implementerebbero semplicemente java.nio.file.spi.FileTypeDetector , lascerai cadere il vaso preferito della libreria di implementazione preferita file nel tuo percorso di classe e sarebbe così.

Nel mondo reale, quello in cui hai bisogno di TL, sezione DR, dovresti trovare la libreria con la maggior parte delle stelle accanto al suo nome e usarla. Per questo caso particolare, non ne ho bisogno (ancora;)).


3

Ho provato diversi modi per farlo, compresi i primi detti da @Joshua Fox. Ma alcuni non riconoscono i mimetipi frequenti come per i file PDF e altri non sono affidabili con file falsi (ho provato con un file RAR con estensione modificata in TIF). La soluzione che ho trovato, come dice anche @Joshua Fox in modo superficiale, è usare MimeUtil2 , in questo modo:

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

5
Non ho avuto alcun successo con MimeUtil2: quasi tutto è tornato come application / octet-stream. Ho usato MimeUtil.getMimeTypes () con molto più successo dopo l'inizializzazione con `MimeUtil.registerMimeDetector (" eu.medsea.mimeutil.detector.MagicMimeMimeDetector "); MimeUtil.registerMimeDetector ( "eu.medsea.mimeutil.detector.ExtensionMimeDetector"); MimeUtil.registerMimeDetector ( "eu.medsea.mimeutil.detector.OpendesktopMimeDetector"); `
Brian Pipa,

2
Grazie per la soluzione funzionante. La documentazione di mime-util non è molto chiara su come creare un'istanza della classe di utilità. Alla fine è stato installato e funzionante, ma ha sostituito la stringa classname con la classe effettiva. MimeUtil.registerMimeDetector (ExtensionMimeDetector.class.getName ()); String mimeType = MimeUtil.getMostSpecificMimeType (MimeUtil.getMimeTypes (nome file)). ToString ();
Rob Juurlink,

2

È meglio utilizzare la convalida a due livelli per il caricamento dei file.

Per prima cosa puoi verificare il mimeType e convalidarlo.

Secondo, dovresti cercare di convertire i primi 4 byte del tuo file in esadecimali e poi confrontarlo con i numeri magici. Quindi sarà un modo davvero sicuro per verificare la convalida dei file.


2

Questo è il modo più semplice che ho trovato per fare questo:

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

Ottima soluzione!
Sherzod,

2

Se si lavora con un servlet e se il contesto del servlet è disponibile, è possibile utilizzare:

getServletContext().getMimeType( fileName );

1
Che cosa è getServletContext?
e-info128

1

in primavera file MultipartFile ;

org.springframework.web.multipart.MultipartFile

file.getContentType();


0

se lavori su un sistema operativo Linux, esiste una riga di comando 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 "";
}

Poi

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

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

2
Funzionerà, ma IMO è una cattiva pratica poiché lega il codice a un sistema operativo specifico e richiede che l'utilità esterna sia presente sul sistema che lo esegue. Non fraintendetemi; è una soluzione completamente valida, ma rompe la portabilità - che è uno dei motivi principali per utilizzare Java in primo luogo ...
ToVine

@ToVine: Per la cronaca, sarò rispettosamente in disaccordo. Non tutti i programmi Java devono essere portatili. Lascia che sia il contesto sia il programmatore a prendere quella decisione. en.wikipedia.org/wiki/Java_Native_Interface
Zahnon

0

Dopo aver provato varie altre biblioteche, ho optato per 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;
}

Questo metodo Files.probeContentType (String) è disponibile dalla versione 1.7 di JDK e funziona molto bene per me.
Reza Rahimi,

Grazie, solo non riesco a capire perché alcuni utenti abbiano votato in giù)))
Vazgen Torosyan

Niente affatto, forse hanno una versione precedente di JDK :)))
Reza Rahimi,

0

Puoi farlo con una sola riga: MimetypesFileTypeMap (). GetContentType (nuovo file ("filename.ext")) . Guarda il codice di prova completo (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")));
    }
}

Questo codice produce il seguente output: 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
Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post.
Shree,

0

L'ho fatto con il seguente codice.

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>

e due righe di codice.

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

Screenshot sotto

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.