Java'da Dosyanın Mime Türünü Alma


336

Sadece çoğu insanın Java'daki bir dosyadan nasıl bir mime türü aldığını merak ediyordum? Şimdiye kadar iki araç denedim: JMimeMagic& Mime-Util.

Birincisi bana bellek istisnaları verdi, ikincisi akışlarını düzgün bir şekilde kapatmıyor. Ben sadece başkalarının kullandıkları yöntem ve kütüphane doğru kullandım ve doğru çalışıp çalışmadığını merak ediyordum?


4
Mevcut kütüphanelere iyi bir genel bakış rgagnon.com/javadetails/java-0487.html
koppor

Burada cevap olarak verilen sınıfı kullandım: stackoverflow.com/a/10140531/293280
Joshua Pinter

3
Şimdi Tika cevap olmalı. Aşağıdaki diğer cevaplar Tika ile birçok bağımlılığı aydınlatıyor, ancak tika çekirdeği ile hiçbiri görmüyorum.
javamonkey79

@ javamonkey79 TIka kullandığımızda dosyayı kapatıyor ve artık kullanılamıyor. String contentType = tika.detect (is).
Cool Techie

Yanıtlar:


326

Java 7'de artık kullanabilirsiniz Files.probeContentType(path).


62
Files.probeContentType (Path) uygulamasının birkaç işletim sisteminde hatalı olduğunu ve birçok hata raporunun dosyalandığını unutmayın. Ubuntu üzerinde çalışan ancak pencerelerde başarısız olan bir sorunla karşılaştım. Windows Files.probeContentType (Yol) her zaman null döndürdü görünüyordu. Bu benim sistemim değildi, bu yüzden JRE veya windows sürümünü kontrol etmedim. Java 7 için muhtemelen Jracle ile 7 veya 8 pencerelerdi.
Silver

13
Ben OS X 10.9 üzerinde çalışan ve ben almak nulliçin dışarı .xml, .pngve .xhtmldosyalar. Sadece korkunç bir şekilde yanlış bir şey yapıp yapmadığımı bilmiyorum, ama bu oldukça korkunç görünüyor.

36
Bununla ilgili büyük bir sınırlama, dosyanın dosya sisteminde bulunması gerektiğidir. Bu bir akış veya bayt dizisi vb.
İle çalışmaz

3
adı test.mp4 i "test" haline değiştirmektir ve metot bize i değişiklik film uzantısını null.Also eğer bu yöntem i name.For xmaple uzantıyı kaldırdığınızda mim türü döndüremez png vb o mim türü png döndürür
Sarkhan

10
Dosyanın eksik veya yanlış uzantısı varsa bu işe yaramaz.
shmosel

215

Ne yazık ki,

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

URL'nin bu kullanımı bir dosyayı kilitli bıraktığından, örneğin silinemez olması için çalışmaz.

Ancak, bu var:

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

ve ayrıca, yalnızca dosya uzantısını kullanmanın ötesine geçme avantajına sahip olan ve içeriğe bir göz atan

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

Bununla birlikte, yukarıdaki yorumda önerildiği gibi, mime tiplerinin yerleşik tablosu oldukça sınırlıdır, örneğin MSWord ve PDF dahil değildir. Bu nedenle, genelleştirmek istiyorsanız, örneğin Mime-Util'i (hem dosya uzantısı hem de içerik kullanan harika bir kütüphane olan) kullanarak yerleşik kitaplıkların ötesine geçmeniz gerekir.


8
Mükemmel çözüm - bana çok yardımcı oldu! Sarma FileInputStreamiçine BufferedInputStreamaksi - çok önemli bir parçasıdır guessContentTypeFromStreamdöner null(geçirilen InputStreamörneği işaretleri desteklemelidir)
Yuriy Nakonechnyy

11
Howerver, tanıdığı URLConnectionçok sınırlı bir içerik türüne sahiptir. Örneğin algılayamıyor application/pdf.
kpentchev

3
Sadece kilitli bırakır, çünkü kendinize onu kapatmanın bir yolunu bırakmadınız. URLConnection bağlantısının kesilmesi kilidini açar.
Lorne Marquis

1
hem guessContentTypeFromStream ne de guessContentTypeFromName tanımıyor örn. mp4
Hartmut P.

3
guessContentTypeFromName()varsayılan $JAVA_HOME/lib/content-types.propertiesdosyayı kullanır . sistem özelliğini değiştirerek kendi genişletilmiş dosyanızı ekleyebilirsinizSystem.setProperty("content.types.user.table","/lib/path/to/your/property/file");
Rasika Perera

50

JAF API, JDK 6'nın bir parçasıdır. javax.activationPakete bakın .

En ilginç sınıflar javax.activation.MimeType- gerçek bir MIME türü sahibi - ve javax.activation.MimetypesFileTypeMapörneği MIME türünü bir dosya için Dize olarak çözebilen sınıftır:

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
Ne yazık ki, getContentType(File)durumlar için javadoc olarak : Dosya nesnesinin MIME türünü döndürür.Bu sınıftaki uygulama çağırır getContentType(f.getName()).
Matyas

3
Ve bu işlevi META-INF / mime.types dosyasıyla genişletebileceğinizi unutmayın, böylece Java 6'yı kullanmak zorunda kalmanız mükemmel olur. Docs.oracle.com/javaee/5/api/javax/activation/…
Chexpir

8
yeni bir nesne oluşturmayı atlayabilirsinizMimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(file)
akostadinov

Cevabınız için teşekkürler. Benim için başarıyla çalışıyor.
Radadiya Nikunj

Ancak yine de yalnızca dosya adına göre içerik türü döndürür. Ve bu özellikle kullanıcılar tarafından yüklenen dosyalar için tehlikelidir.
Sergey Ponomarev

47

Apache Tika ile sadece üç satır kod gerekir :

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

Mükemmel bir konsolunuz varsa, onunla oynamak için bu kodu yapıştırın ve çalıştırın:

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

API'lerinin zengin olduğunu ve "her şeyi" ayrıştırabileceğini unutmayın. Tika-çekirdek 1.14'ten itibaren:

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)

Daha fazla bilgi için apidoklara bakınız .


1
Csv için çalışmaz. o ne lan? stackoverflow.com/questions/46960231/…
gstackoverflow

1
Tika hakkında kötü bir şey, çok sayıda bağımlılık şişmesi. Kavanozumun boyutunu 54MB artırdı !!!
helmy

1
@helmyTika 1.17 bağımsızdır ve yalnızca 648 KB boyutundadır.
Sainan

... veya new Tika().detect(file.toPath())dosyanın içeriğine dayalı algılama yerine dosyanın uzantı tabanlı algılaması için
Lu55

@ Lu55 dokümanları hala belge içeriğini kullandığını söylüyor. Bence new Tika().detect(file.getPath())sadece dosya uzantısını kullanan
delucasvb

31

Apache Tika , tika çekirdeğinde , akış önekindeki sihirli işaretleyicilere dayanan bir mime tipi algılama sunar. tika-corediğer bağımlılıkları getirmez, bu da onu şu anda korunmayan Mime Tipi Algılama Yardımcı Programı kadar hafif yapar .

Basit kod örneği (Java 7), değişkenleri theInputStreamvetheFileName

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

Lütfen MediaType.detect (...) öğesinin doğrudan kullanılamayacağını unutmayın ( TIKA-1120 ). Daha fazla ipucu https://tika.apache.org/0.10/detection.html adresinde sunulmaktadır .


1
+1 Ayrıca Metadata.RESOURCE_NAME_KEYatlanabilir (orijinal adınız yoksa veya orijinal isme güvenemiyorsanız), ancak bu durumda bazı durumlarda yanlış sonuç elde edersiniz (örneğin ofis belgeleri).
user1516873

Dosya adında uzantı yoksa XLSX'i tespit etmekte bazı sorunlar var ... ancak bu çözüm basit ve zariftir.
Oscar Pérez

23

Android geliştiricisiyseniz bir yardımcı program sınıfı kullanabilirsiniz android.webkit.MimeTypeMap MIME türlerini dosya uzantılarıyla veya tam tersini eşleyen .

Aşağıdaki kod snippet'i size yardımcı olabilir.

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

3
Bu, "/sdcard/path/to/video.extension" gibi yerel dosya yollarıyla da denenirse çalışır. Sorun, yerel dosya yolunda boşluk içeriyorsa, her zaman null döndürür
nmxprime

17

Gönderen roseindia :

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

7
Cevabı kim düşürdüyse, lütfen bir yorum ekleyin, böylece ben (ve diğerleri) daha iyi cevaplar yayınlamayı öğrenebiliriz.
AlikElzin-kilaka

3
Size oy vermedim, ancak getFileNameMap 'bmp' gibi birçok temel dosya türü için çalışmıyor. Ayrıca URLConnection.guessContentTypeFromName aynı şeyi döndürür
Ovidiu Buligan

5
Çok eksik fonksiyon. Java 7'den itibaren html, pdf ve jpeg uzantıları doğru mime türünü döndürür, ancak js ve css null döndürür!
djsumdog

Ben 'webm' ile test ve null döndü.
Henrique Rocha

16

Java 5-6 ile sıkışmışsanız , servoy açık kaynaklı üründen bu yardımcı sınıf .

Sadece bu işleve ihtiyacınız var

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

İçeriğin ilk baytını inceler ve dosya türüne göre değil, o içeriğe göre içerik türlerini döndürür.



13

Sadece çoğu insanın Java'daki bir dosyadan nasıl bir mime türü aldığını merak ediyordum?

Dosyalardan ve bayt dizilerinden içerik türü (mime türü) belirlemesine izin veren SimpleMagic Java paketimi yayınladım . Çoğu ~ Unix OS yapılandırmasının bir parçası olan Unix dosyası (1) komut sihirli dosyalarını okumak ve çalıştırmak için tasarlanmıştır.

Apache Tika'yı denedim ama tonlarca bağımlılık ile çok büyükURLConnection , dosyaların baytlarını kullanmıyor veMimetypesFileTypeMap sadece dosya adlarına bakıyor.

SimpleMagic ile aşağıdakileri yapabilirsiniz:

// 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
Birden fazla görüntü dosyasında test edilmiştir. Tümünün uzantısı yeniden adlandırıldı. Harika kütüphaneniz bunu düzgün bir şekilde halletti. Tabii ki ışığı da :).
saurabheights

1
Evet, bu iyi çalışıyor. Ve bu çözümü Android içinde kullanmak isteyenler için, build.gradle dosyasına şunları dahil edebilirsiniz: compile ('com.j256.simplemagic: simplemagic: 1.10')
jkincali

1
Bu harika bir çözüm! Teşekkürler!
javydreamercsw

5

5 sent ile giriş yapmak için:

TP, DR

MimetypesFileTypeMap kullanın ve orada olmayan herhangi bir mime ekleyin ve özellikle mime.types dosyasına ihtiyaç duyuyorum.

Ve şimdi, uzun okuma:

Her şeyden önce, MIME türleri listesi çok büyük , buraya bakın: https://www.iana.org/assignments/media-types/media-types.xhtml

Öncelikle JDK tarafından sağlanan standart olanakları kullanmayı seviyorum ve bu işe yaramazsa, gidip başka bir şey arayacağım.

Dosya uzantısından dosya türünü belirleme

1.6'dan beri Java, yukarıdaki cevaplardan birinde işaret edildiği gibi MimetypesFileTypeMap'e sahiptir ve mime türünü belirlemenin en basit yoludur:

new MimetypesFileTypeMap().getContentType( fileName );

Vanilya uygulamasında bu pek bir şey yapmaz (yani .html için çalışır, ancak .png için çalışmaz). Bununla birlikte, ihtiyacınız olabilecek herhangi bir içerik türünü eklemek çok basittir:

  1. Projenizdeki META-INF klasöründe 'mime.types' adlı bir dosya oluşturun
  2. İhtiyacınız olan ve varsayılan uygulamanın sağlamadığı her mim türü için bir satır ekleyin (yüzlerce mim türü vardır ve zaman geçtikçe liste büyür).

Png ve js dosyaları için örnek girişler:

image/png png PNG
application/javascript js

Mime.types dosya biçimi için daha fazla ayrıntıya buradan bakın: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html

Dosya içeriğinden dosya türünü belirleme

1.7'den beri Java, bir dosya türünü uygulamaya özel bir şekilde belirlemek için standart bir API tanımlayan java.nio.file.spi.FileTypeDetector'a sahiptir .

Bir dosya için mime türünü getirmek için Dosyalar'ı kullanmanız ve bunu kodunuzda yapmanız yeterlidir :

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

API tanımı, dosya adından veya dosya içeriğinden (sihirli bayt) dosya mime türünün belirlenmesini destekleyen özellikler sağlar. Bu yüzden probeContentType () , bu API'nin bir uygulamasının, kendisiyle ilişkilendirilmiş dosyayı açmaya çalışmak için kendisine sağlanan durumunda yöntemi IOException özel durumunu oluşturur.

Yine vanilya uygulaması (JDK ile birlikte gelen) arzulanan çok şey bırakıyor.

Uzak, çok uzak bir galaksideki bazı ideal dünyada, bu dosyadan mime tipi sorunu çözmeye çalışan tüm bu kütüphaneler java.nio.file.spi.FileTypeDetector'ı uygular , tercih edilen uygulama kütüphanesinin kavanozuna sınıf yolunuza dosya ve bu olurdu.

TL, DR bölümüne ihtiyacınız olan gerçek dünyada, adının yanında en çok yıldız bulunan kütüphaneyi bulmalı ve kullanmalısınız. Bu özel durum için bir (henüz;)) ihtiyacım yok.


3

@Joshua Fox tarafından söylenen ilk olanlar da dahil olmak üzere bunu yapmanın birkaç yolunu denedim. Ancak bazıları PDF dosyaları gibi sık mime türlerini tanımıyor ve diğerleri sahte dosyalar ile güvenilir olamazdı (uzantısı TIF olarak değiştirilmiş bir RAR dosyası ile denedim). @Joshua Fox tarafından yüzeysel bir şekilde söylendiği gibi bulduğum çözüm , MimeUtil2'yi şu şekilde kullanmaktır :

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

5
MimeUtil2 ile hiç başarılı olamadım - neredeyse her şey uygulama / octet-stream olarak geri geldi. MimeUtil.registerMimeDetector ("eu.medsea.mimeutil.detector.MagicMimeMimeDetector") ile başlattıktan sonra MimeUtil.getMimeTypes () yöntemini çok daha başarılı bir şekilde kullandım; MimeUtil.registerMimeDetector ( "eu.medsea.mimeutil.detector.ExtensionMimeDetector"); MimeUtil.registerMimeDetector ( "eu.medsea.mimeutil.detector.OpendesktopMimeDetector"); ``
Brian Pipa

2
Çalışma çözümü için teşekkürler. Mime-util'in dokümantasyon, faydalı sınıfın nasıl somutlaştırılacağı konusunda çok açık değildir. Sonunda kalktı ve çalışıyor, ancak classname dizesini gerçek sınıfla değiştirdi. MimeUtil.registerMimeDetector (ExtensionMimeDetector.class.getName ()); Dize mimeType = MimeUtil.getMostSpecificMimeType (MimeUtil.getMimeTypes (dosyaadı)). ToString ();
Rob Juurlink

2

Dosya yüklemek için iki katman doğrulaması kullanmak daha iyidir.

İlk önce mimeType'ı kontrol edebilir ve doğrulayabilirsiniz.

İkincisi, dosyanızın ilk 4 baytını onaltılık biçime dönüştürmeli ve ardından sihirli sayılarla karşılaştırmalısınız. O zaman dosya doğrulamalarını kontrol etmek gerçekten güvenli bir yol olacaktır.


2

Bunu yapmak için bulduğum en basit yol budur:

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

En iyi çözüm!
Sherzod

2

Bir Servlet ile çalışıyorsanız ve sunucu uygulaması bağlamı kullanabiliyorsanız şunları kullanabilirsiniz:

getServletContext().getMimeType( fileName );

1
Nedir getServletContext?
e-info128

1

ilkbaharda MultipartFile dosyası;

org.springframework.web.multipart.MultipartFile

file.getContentType();


0

Linux işletim sisteminde çalışıyorsanız, bir komut satırı vardır 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 "";
}

Sonra

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

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

2
Bu işe yarayacaktır, ancak IMO, kodunuzu belirli bir işletim sistemine bağladığı ve harici yardımcı programın onu çalıştıran sistemde bulunmasını gerektirdiği için kötü bir uygulamadır. Beni yanlış anlamayın; Bu tamamen geçerli bir çözümdür, ancak taşınabilirliği
bozar

@ToVine: Kayıt için saygıyla katılmıyorum. Her Java programının taşınabilir olması gerekmez. Bağlam ve programcı bu kararı versin. en.wikipedia.org/wiki/Java_Native_Interface
Zahnon

0

Diğer kütüphaneleri denedikten sonra mime-util ile yerleştim.

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

Bu yöntem Files.probeContentType (String) JDK sürüm 1.7'den beri kullanılabilir ve benim için çok iyi çalışıyor.
Reza Rahimi

Teşekkürler, sadece bazı kullanıcıların neden oy
verdiğini

Hiç de değil, belki daha önceki bir JDK sürümüne sahipler :)))
Reza Rahimi

0

Bunu sadece bir satırla yapabilirsiniz: MimetypesFileTypeMap (). GetContentType (new File ("filename.ext")) . Tam test koduna bakın (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")));
    }
}

Bu kod aşağıdaki çıktıyı üretir: 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
Bu kod soruyu çözebilir, ancak bir açıklama dahil olmak , yayınınızın kalitesini artırmaya yardımcı olur.
Shree

0

Aşağıdaki kod ile yaptım.

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>

ve İki satırlık kod.

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

Aşağıdaki ekran görüntüsü

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.