Mendapatkan Jenis Mime File Di Jawa

336

Saya hanya ingin tahu bagaimana kebanyakan orang mengambil tipe mime dari sebuah file di Java? Sejauh ini saya sudah mencoba dua utilities: JMimeMagic& Mime-Util.

Yang pertama memberi saya pengecualian memori, yang kedua tidak menutup alirannya dengan benar. Saya hanya ingin tahu apakah ada orang lain yang memiliki metode / perpustakaan yang mereka gunakan dan bekerja dengan benar?

Lee Theobald
sumber
4
Tinjauan yang baik tentang perpustakaan yang tersedia diberikan di rgagnon.com/javadetails/java-0487.html
koppor
Saya menggunakan kelas yang diposting sebagai jawaban di sini: stackoverflow.com/a/10140531/293280
Joshua Pinter
3
Tika harus menjadi jawabannya sekarang. Jawaban lain di bawah ini menjelaskan banyak ketergantungan dengan Tika, tetapi saya tidak melihat satupun dengan tika-core.
javamonkey79
@ javamonkey79 ketika kita menggunakan TIka, itu menutupi file dan itu tidak lagi dapat digunakan. String contentType = tika.detect (is).
Cool Techie

Jawaban:

326

Di Java 7 sekarang Anda bisa menggunakannya Files.probeContentType(path).

Chris Mowforth
sumber
62
Sadarilah bahwa Files.probeContentType (Path) bermasalah pada beberapa OS dan banyak laporan bug telah diajukan. Saya memiliki masalah dengan perangkat lunak yang bekerja di ubuntu tetapi gagal di windows. Tampaknya pada windows Files.probeContentType (Path) selalu kembali nol. Itu bukan sistem saya jadi saya tidak memeriksa versi JRE atau windows. Itu windows 7 atau 8 mungkin dengan JRE oracle untuk java 7.
Perak
13
Aku berjalan di OS X 10.9 dan saya mendapatkan nullkeluar untuk .xml, .pngdan .xhtmlfile. Saya tidak tahu apakah saya hanya melakukan sesuatu yang sangat salah, tetapi itu agak mengerikan.
36
Keterbatasan utama dengan ini adalah bahwa file tersebut harus ada pada sistem file. Ini tidak berfungsi dengan stream atau array byte, dll.
Necreaux
3
metode ini tidak dapat mengembalikan tipe mime ketika saya menghapus ekstensi dari nama. Untuk exmaple jika nama test.mp4 saya mengubahnya menjadi "test" dan metode mengembalikan null. Juga saya mengubah ekstensi film ke png dll. mengembalikan tipe
pime
10
Ini tidak berguna jika file tersebut memiliki ekstensi yang hilang atau salah.
shmosel
215

Sayangnya,

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

tidak berfungsi, karena penggunaan URL ini membuat file terkunci, sehingga, misalnya, tidak dapat dihapus.

Namun, Anda memiliki ini:

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

dan juga yang berikut, yang memiliki keuntungan melampaui penggunaan ekstensi file belaka, dan mengintip konten

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

Namun, seperti yang disarankan oleh komentar di atas, tabel bawaan tipe mime cukup terbatas, tidak termasuk, misalnya, MSWord dan PDF. Jadi, jika Anda ingin menggeneralisasi, Anda harus melampaui pustaka built-in, menggunakan, misalnya, Mime-Util (yang merupakan pustaka hebat, menggunakan ekstensi file dan konten).

Joshua Fox
sumber
8
Solusi sempurna - banyak membantu saya! Pembungkus FileInputStreamke BufferedInputStreammerupakan bagian penting - jika tidak guessContentTypeFromStreamkembali null(lulus InputStreammisalnya harus mendukung tanda)
Yuriy Nakonechnyy
11
Howerver, URLConnectionmemiliki satu set tipe konten yang sangat terbatas yang dikenali. Misalnya tidak dapat dideteksi application/pdf.
kpentchev
3
Itu hanya membiarkannya terkunci karena Anda tidak dapat menutupnya. Memutuskan sambungan URLC akan membukanya.
Marquis of Lorne
1
baik guessContentTypeFromStream maupun guessContentTypeFromName TIDAK mengenali mis. mp4
Hartmut P.
3
guessContentTypeFromName()menggunakan $JAVA_HOME/lib/content-types.propertiesfile default . Anda dapat menambahkan file Anda sendiri dengan mengubah properti sistemSystem.setProperty("content.types.user.table","/lib/path/to/your/property/file");
Rasika Perera
50

API JAF adalah bagian dari JDK 6. Lihat javax.activationpaket.

Kelas yang paling menarik adalah javax.activation.MimeType- pemegang tipe MIME aktual - dan javax.activation.MimetypesFileTypeMap- kelas yang instansinya dapat menyelesaikan tipe MIME sebagai String untuk 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);
Adam Hošek
sumber
4
Sayangnya, sebagai javadoc untuk getContentType(File)negara: Mengembalikan tipe MIME dari objek file. Implementasinya di kelas ini memanggil getContentType(f.getName()).
Matya
3
Dan ingat Anda dapat memperluas fungsionalitas ini dengan file META-INF / mime.types sehingga sangat sempurna jika Anda terpaksa menggunakan Java 6. docs.oracle.com/javaee/5/api/javax/activation/…
Chexpir
8
Anda dapat melewatkan membuat objek baru denganMimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(file)
akostadinov
Terima kasih atas jawaban anda. Ini berhasil bekerja untuk saya.
Radadiya Nikunj
Tetapi masih mengembalikan tipe konten hanya berdasarkan nama file. Dan ini sangat berbahaya untuk file yang diunggah oleh pengguna.
Sergey Ponomarev
47

Dengan Apache Tika Anda hanya perlu tiga baris kode :

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

Jika Anda memiliki konsol asyik, cukup rekatkan dan jalankan kode ini untuk bermain dengannya:

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

Perlu diingat bahwa API-nya kaya, ia dapat menguraikan "apa saja". Pada tika-core 1.14, Anda memiliki:

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)

Lihat apidocs untuk informasi lebih lanjut.

lifeisfoo
sumber
1
Itu tidak bekerja untuk csv. wtf? stackoverflow.com/questions/46960231/…
gstackoverflow
1
Satu hal buruk tentang Tika, banyak ketergantungan menggembung. Ini meningkatkan ukuran toples saya sebesar 54MB !!!
Helmy
1
@helmyTika 1.17 standalone dan hanya 648 KB besar.
Sainan
... atau hanya new Tika().detect(file.toPath())untuk deteksi berbasis ekstensi file daripada deteksi berdasarkan konten file
Lu55
@ Lu55 docs mengatakan bahwa masih menggunakan konten dokumen. Saya pikir maksud Anda new Tika().detect(file.getPath()), yang hanya menggunakan ekstensi file
delucasvb
31

Apache Tika menawarkan di tika-core deteksi tipe mime berdasarkan marka sihir pada awalan stream. tika-coretidak mengambil dependensi lain, yang membuatnya seringan Utilitas Deteksi Tipe Mime yang saat ini tidak terawat .

Contoh kode sederhana (Java 7), menggunakan variabel theInputStreamdantheFileName

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

Harap dicatat bahwa MediaType.detect (...) tidak dapat digunakan secara langsung ( TIKA-1120 ). Petunjuk lainnya disediakan di https://tika.apache.org/0.10/detection.html .

koppor
sumber
1
+1 Juga Metadata.RESOURCE_NAME_KEYdapat dihilangkan (jika Anda tidak memiliki atau tidak dapat mengandalkan nama asli), tetapi dalam hal ini Anda akan mendapatkan hasil yang salah dalam beberapa kasus (misalnya dokumen kantor).
user1516873
Ini memiliki beberapa masalah dalam mendeteksi XLSX jika tidak ada ekstensi pada nama file ... tetapi solusi ini sederhana dan elegan.
Oscar Pérez
23

Jika Anda seorang pengembang Android, Anda dapat menggunakan kelas utilitas android.webkit.MimeTypeMap yang memetakan tipe-MIME untuk mengajukan ekstensi dan sebaliknya.

Cuplikan kode berikut dapat membantu Anda.

private static String getMimeType(String fileUrl) {
    String extension = MimeTypeMap.getFileExtensionFromUrl(fileUrl);
    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
Pawan
sumber
3
Ini juga berfungsi jika dicoba dengan path file lokal seperti "/sdcard/path/to/video.extension". Masalahnya adalah jika file lokal berisi ruang di jalurnya, selalu mengembalikan null
nmxprime
17

Dari roseindia :

FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimeType = fileNameMap.getContentTypeFor("alert.gif");
AlikElzin-kilaka
sumber
7
Siapa pun yang memilih jawaban, silakan tambahkan komentar sehingga saya (dan orang lain) dapat belajar memposting jawaban yang lebih baik.
AlikElzin-kilaka
3
Saya tidak memilih Anda, tetapi, getFileNameMap tidak berfungsi untuk banyak jenis file dasar, misalnya 'bmp'. Juga URLConnection.guessContentTypeFromName mengembalikan hal yang sama
Ovidiu Buligan
5
Fungsi yang sangat tidak lengkap. Pada Java 7, ekstensi html, pdf dan jpeg mengembalikan tipe mime yang benar tetapi js dan css mengembalikan null!
djsumdog
Saya diuji dengan 'webm' dan hasilnya nol.
Henrique Rocha
16

Jika Anda terjebak dengan java 5-6 maka kelas utilitas ini dari produk open source servoy .

Anda hanya perlu fungsi ini

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

Ini menyelidiki byte pertama dari konten dan mengembalikan tipe konten berdasarkan konten itu dan bukan dengan ekstensi file.

Ovidiu Buligan
sumber
Bekerja untuk jenis file sederhana, populer, dan beberapa yang saya butuhkan :)
user489041
13

Saya hanya ingin tahu bagaimana kebanyakan orang mengambil tipe mime dari sebuah file di Java?

Saya telah menerbitkan SimpleMagic saya paket Java yang memungkinkan penentuan tipe-tipe (tipe-mime) dari file dan byte array. Ini dirancang untuk membaca dan menjalankan file Unix (1) perintah file ajaib yang merupakan bagian dari sebagian besar ~ konfigurasi OS Unix.

Saya mencoba Apache Tika tetapi sangat besar dengan banyak dependensi, URLConnectiontidak menggunakan byte file, dan MimetypesFileTypeMapjuga hanya melihat nama file.

Dengan SimpleMagic Anda dapat melakukan sesuatu seperti:

// 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();
}
Abu-abu
sumber
1
Mengujinya pada banyak file gambar. Semua ekstensi berganti nama. Pustaka Anda yang luar biasa menanganinya dengan benar. Tentu saja cahayanya :).
saurabheights
1
Ya, ini bekerja dengan baik. Dan bagi mereka yang perlu menggunakan solusi ini di Android, Anda cukup memasukkan yang berikut ini dalam file build.gradle: compile ('com.j256.simplemagic: simplemagic: 1.10')
jkincali
1
Ini solusi hebat! Terima kasih!
javydreamercsw
5

Untuk mengimbangi 5 sen saya:

TL, DR

Saya menggunakan MimetypesFileTypeMap dan menambahkan mime yang tidak ada di sana dan saya secara khusus membutuhkannya, ke dalam file mime.types.

Dan sekarang, yang lama dibaca:

Pertama-tama, daftar jenis MIME sangat besar , lihat di sini: https://www.iana.org/assignments/media-types/media-types.xhtml

Saya suka menggunakan fasilitas standar yang disediakan oleh JDK terlebih dahulu, dan jika itu tidak berhasil, saya akan pergi dan mencari yang lain.

Tentukan jenis file dari ekstensi file

Sejak 1.6, Java memiliki MimetypesFileTypeMap, seperti yang ditunjukkan dalam salah satu jawaban di atas, dan ini adalah cara paling sederhana untuk menentukan tipe mime:

new MimetypesFileTypeMap().getContentType( fileName );

Dalam implementasi vanilla ini tidak banyak membantu (yaitu berfungsi untuk .html tetapi tidak untuk .png). Namun, sangat sederhana untuk menambahkan jenis konten apa pun yang Anda butuhkan:

  1. Buat file bernama 'mime.types' di folder META-INF di proyek Anda
  2. Tambahkan baris untuk setiap jenis mime yang Anda butuhkan dan implementasi default tidak memberikan (ada ratusan jenis mime dan daftar bertambah seiring berjalannya waktu).

Contoh entri untuk file png dan js adalah:

image/png png PNG
application/javascript js

Untuk format file mime.types, lihat detail lebih lanjut di sini: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html

Tentukan jenis file dari konten file

Sejak 1.7, Java memiliki java.nio.file.spi.FileTypeDetector , yang mendefinisikan API standar untuk menentukan tipe file dalam implementasi yang spesifik .

Untuk mengambil tipe mime untuk file, Anda cukup menggunakan File dan melakukan ini dalam kode Anda:

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

Definisi API menyediakan fasilitas yang mendukung untuk menentukan jenis pantomim file dari nama file atau dari konten file (byte ajaib). Itu sebabnya probeContentType () metode melempar IOException, jika implementasi API ini menggunakan Path yang disediakan untuk benar-benar mencoba membuka file yang terkait dengannya.

Sekali lagi, implementasi vanilla ini (yang datang dengan JDK) meninggalkan banyak hal yang diinginkan.

Di beberapa dunia ideal di galaksi yang sangat jauh, semua pustaka yang mencoba memecahkan masalah tipe file-to-mime ini hanya akan mengimplementasikan java.nio.file.spi.FileTypeDetector , Anda akan memasukkan jar perpustakaan implementasi yang disukai file ke classpath Anda dan hanya itu.

Di dunia nyata, bagian tempat Anda membutuhkan TL, DR, Anda harus menemukan perpustakaan dengan sebagian besar bintang di sebelah namanya dan menggunakannya. Untuk kasus khusus ini, saya tidak perlu satu (belum;)).

nidalpres
sumber
3

Saya mencoba beberapa cara untuk melakukannya, termasuk yang pertama dikatakan oleh @ Yosua Fox. Tetapi beberapa tidak mengenali mimetipe seperti untuk file PDF, dan lainnya tidak dapat dipercaya dengan file palsu (saya mencoba dengan file RAR dengan ekstensi diubah menjadi TIF). Solusi yang saya temukan, seperti juga dikatakan oleh @Joshua Fox dengan cara yang dangkal, adalah dengan menggunakan MimeUtil2 , seperti ini:

MimeUtil2 mimeUtil = new MimeUtil2();
mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
String mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file)).toString();
ricardoc
sumber
5
Saya tidak berhasil sama sekali dengan MimeUtil2 - hampir semuanya kembali sebagai application / octet-stream. Saya menggunakan MimeUtil.getMimeTypes () dengan lebih sukses setelah menginisialisasi dengan `MimeUtil.registerMimeDetector (" eu.medsea.mimeutil.detector.MagicMimeMimeDetector "); MimeUtil.registerMimeDetector ("eu.medsea.mimeutil.detector.ExtensionMimeDetector"); MimeUtil.registerMimeDetector ("eu.medsea.mimeutil.detector.OpendesktopMimeDetector"); `
Brian Pipa
2
Terima kasih atas solusinya. Dokumentasi mime-util tidak begitu jelas tentang cara membuat instance kelas utilitas. Akhirnya bangkit dan berjalan, tetapi mengganti string classname dengan kelas yang sebenarnya. MimeUtil.registerMimeDetector (ExtensionMimeDetector.class.getName ()); String mimeType = MimeUtil.getMostSpecificMimeType (MimeUtil.getMimeTypes (nama file)). ToString ();
Rob Juurlink
2

Lebih baik menggunakan validasi dua lapisan untuk mengunggah file.

Pertama, Anda dapat memeriksa mimeType dan memvalidasinya.

Kedua Anda harus melihat untuk mengkonversi 4 byte pertama dari file Anda ke heksadesimal dan kemudian membandingkannya dengan angka ajaib. Maka itu akan menjadi cara yang sangat aman untuk memeriksa validasi file.

javacreed
sumber
2

Ini adalah cara paling sederhana yang saya temukan untuk melakukan ini:

byte[] byteArray = ...
InputStream is = new BufferedInputStream(new ByteArrayInputStream(byteArray));
String mimeType = URLConnection.guessContentTypeFromStream(is);
madx
sumber
Solusi terbaik!
Sherzod
2

Jika Anda bekerja dengan Servlet dan jika konteks servlet tersedia untuk Anda, Anda dapat menggunakan:

getServletContext().getMimeType( fileName );
Ramishka Dasanayaka
sumber
1
Apa getServletContext?
e-info128
1

dalam file MultipartFile musim semi ;

org.springframework.web.multipart.MultipartFile

file.getContentType();

Ahmad R. Nazemi
sumber
0

jika Anda bekerja di OS linux, ada baris perintah 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 "";
}

Kemudian

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

mimetype("/var/www/ggg/au.mp3") //  'audio/mp3'
Abdennour TOUMI
sumber
2
Ini akan berhasil, tetapi IMO merupakan praktik buruk karena mengikat kode Anda ke OS tertentu dan memerlukan utilitas eksternal untuk hadir di sistem yang menjalankannya. Jangan salah sangka; ini adalah solusi yang sepenuhnya valid, tetapi merusak portabilitas - yang merupakan salah satu alasan utama untuk menggunakan Java di tempat pertama ...
ToVine
@ ToVine: Sebagai catatan, saya akan dengan hormat tidak setuju. Tidak semua program Java harus portabel. Biarkan konteks dan programmer membuat keputusan itu. en.wikipedia.org/wiki/Java_Native_Interface
Zahnon
0

Setelah mencoba berbagai pustaka lain saya puas dengan 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);
K. Siva Prasad Reddy
sumber
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;
}
Vazgen Torosyan
sumber
Metode ini Files.probeContentType (String) tersedia sejak JDK versi 1.7 dan bekerja sangat baik untuk saya.
Reza Rahimi
Terima kasih, hanya saya yang tidak mengerti mengapa beberapa pengguna memilih)))
Vazgen Torosyan
Tidak sama sekali, mungkin mereka memiliki versi JDK sebelumnya :)))
Reza Rahimi
0

Anda dapat melakukannya hanya dengan satu baris: MimetypesFileTypeMap (). GetContentType (File baru ("filename.ext")) . Lihat kode tes lengkap (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")));
    }
}

Kode ini menghasilkan output sebagai berikut: teks / polos

Cassio Seffrin
sumber
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();
Ganesh Vechalapu
sumber
4
Sementara kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda.
Shree
0

Saya melakukannya dengan kode berikut.

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

        }
    }
}
sahmad
sumber
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>

dan Dua baris kode.

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

Tangkapan layar di bawah

masukkan deskripsi gambar di sini

Pratik Gaurav
sumber