Como determinar o tipo de arquivo MIME no android?

176

Suponha que eu tenha um caminho completo do arquivo como: (/ sdcard / tlogo.png). Eu quero saber o seu tipo de mímica.

Eu criei uma função para isso

public static String getMimeType(File file, Context context)    
{
    Uri uri = Uri.fromFile(file);
    ContentResolver cR = context.getContentResolver();
    MimeTypeMap mime = MimeTypeMap.getSingleton();
    String type = mime.getExtensionFromMimeType(cR.getType(uri));
    return type;
}

mas quando eu chamo, ele retorna nulo.

File file = new File(filePath);
String fileType=CommonFunctions.getMimeType(file, context);
Sushant Bhatnagar
fonte

Respostas:

323

Em primeiro lugar, considere ligar MimeTypeMap#getMimeTypeFromExtension()assim:

// url = file path or whatever suitable URL you want.
public static String getMimeType(String url) {
    String type = null;
    String extension = MimeTypeMap.getFileExtensionFromUrl(url);
    if (extension != null) {
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return type;
}
Jens
fonte
4
obrigado trabalho para mim e outra solução do meu problema é: public estático String getMimeType (caminho da String, contexto de contexto) {Extensão da string = path.substring (path.lastIndexOf (".")); String mimeTypeMap = MimeTypeMap.getFileExtensionFromUrl (extensão); String mimeType = MimeTypeMap.getSingleton () .getMimeTypeFromExtension (mimeTypeMap); return mimeType;}
Sushant Bhatnagar
13
E se o arquivo não tiver a boa extensão? uma pessoa pode fazer um .mp3 e ele contém texto
throrin19
2
Então, você realmente precisa abrir o arquivo e verificar o número mágico (dependendo do formato ofc) no lead-in - isso, no entanto, também pressupõe que a pessoa que renomeou os arquivos txt para mp3 não apenas escreveu ID3no início do seu texto para mexer com você ainda mais.
Jens
1
Se o arquivo tiver uma extensão desconhecida. O método retorna */*?
3
Se você tiver um caminho de arquivo como / storage / emulated / 0 / Download / images (4) .jpg e solicitar o tipo mimetype, ele retornará nulo.
Kalaiselvan
165

Detectar tipo MIME de qualquer arquivo

public String getMimeType(Uri uri) {           
    String mimeType = null;
    if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
        ContentResolver cr = getAppContext().getContentResolver();
        mimeType = cr.getType(uri);
    } else {
        String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
                .toString());
        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                fileExtension.toLowerCase());
    }
    return mimeType;
}
Hoa Le
fonte
5
Essa deve ser a resposta correta. toLowerCase()fez o truque.
Rajat Saxena
1
Esta é de longe a melhor resposta, mas falha miseravelmente se o nome do arquivo tiver um caractere especial, no meu caso um apostrophe! Por exemplo. nome do arquivo = Don't go baby.mp3. O PatternMatcherinterior MimeTypeMap.getFileExtensionFromUrl()não pode manipular o nome do arquivo e retorna String vazia; null passa a ser o tipo de tipo String!
sud007
Existe uma solução semelhante, mas sem erros, abaixo, da I. ShvedenenkoWorked, para os problemas que eu apontei acima. Mas essa resposta foi um indicador na direção correta.
sud007
esse código retorna nulo com a string "/ storage / emulated / 0 / dcim / screenshots / screenshot_20190319-123828_ubl digital app.jpg".
Abdul
@ Abdul É porque esse caminho não possui um esquema de Uri. Deve começar com file://ou content://.
HB.
33

A solução MimeTypeMap acima retornou nula no meu uso. Isso funciona e é mais fácil:

Uri uri = Uri.fromFile(file);
ContentResolver cR = context.getContentResolver();
String mime = cR.getType(uri);
Jeb
fonte
19
Este método também pode retornar nulo.
Mister Smith
Parece que pode retornar nulo ou não, de acordo com o URI. Nenhum corpo parece saber por que ;-(
Thomas Decaux
10
Se a mídia for selecionada na galeria do Android, TYPE será retornado. Se selecionado no Gerenciador de Arquivos, nulo será retornado.
Rahul Rastogi
Eu posso positivamente confirmar o que Rahul disse, só testei e ele está certo
Chris
Em alguns dispositivos, se eu selecionar uma imagem da galeria também está retornando null
Ghanshyam Nayma
21

Versão otimizada do respondere de Jens com segurança nula e tipo de fallback.

@NonNull
static String getMimeType(@NonNull File file) {
    String type = null;
    final String url = file.toString();
    final String extension = MimeTypeMap.getFileExtensionFromUrl(url);
    if (extension != null) {
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
    }
    if (type == null) {
        type = "image/*"; // fallback type. You might set it to */*
    }
    return type;
}

Importante : getFileExtensionFromUrl () funciona apenas com letras minúsculas !


Atualização (19.03.2018)

Bônus: métodos acima como uma função de extensão Kotlin menos detalhada :

fun File.getMimeType(fallback: String = "image/*"): String {
    return MimeTypeMap.getFileExtensionFromUrl(toString())
            ?.run { MimeTypeMap.getSingleton().getMimeTypeFromExtension(toLowerCase()) }
            ?: fallback // You might set it to */*
}
Tobias
fonte
isso funcionou. um pouco excessivamente detalhado para o meu gosto.
filthy_wizard
É claro que isso pode ser feito de maneira mais curta. Com Kotlin provavelmente apenas duas ou três linhas, no entanto, o foxus estava na segurança e toLoverCaseparte nulas .
Tobias
@filthy_wizard, acrescentou uma versão otimizada para você ;-)
Tobias
Quanto a mim, usar o método getPath () em vez de toString () é mais claro e apenas o caminho usando a sintaxe de acesso à propriedade kotlin.
Leonid
15
File file = new File(path, name);

    MimeTypeMap mime = MimeTypeMap.getSingleton();
    int index = file.getName().lastIndexOf('.')+1;
    String ext = file.getName().substring(index).toLowerCase();
    String type = mime.getMimeTypeFromExtension(ext);

    intent.setDataAndType(Uri.fromFile(file), type);
    try
    {
      context.startActivity(intent);
    }
    catch(ActivityNotFoundException ex)
    {
        ex.printStackTrace();

    }
umerk44
fonte
1
Funciona perfeito para mim! Mas que tal usar o FilenameUtils.getExetension (path) para obter a extensão do arquivo?
Peterb
7

Preste super perto atenção para umerk44 's solução acima. getMimeTypeFromExtensioninvoca guessMimeTypeTypeFromExtensione é sensível a maiúsculas e minúsculas. Passei uma tarde nisso e, em seguida, olhei mais de perto - getMimeTypeFromExtensionretornará NULLse você passá-lo "JPG", enquanto retornará "imagem / jpeg" se passá-lo "jpg".

Mike Kogan
fonte
5

Aqui está a solução que eu usei no meu aplicativo Android:

public static String getMimeType(String url)
    {
        String extension = url.substring(url.lastIndexOf("."));
        String mimeTypeMap = MimeTypeMap.getFileExtensionFromUrl(extension);
        String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(mimeTypeMap);
        return mimeType;
    }
Mahendra Liya
fonte
1
url? Muitos URLs não têm extensão. Por exemplo, esta página não tem extensão. Para url, você deve usar o novo URL (url) .openConnection (). GetRequestProperty ("Content-type");
barwnikk
5

Às vezes, as respostas de Jeb e Jens não funcionam e retornam nulas. Neste caso, eu uso follow solution. O chefe do arquivo geralmente contém assinatura de tipo. Eu li e comparo com o conhecido na lista de assinaturas .

/**
 *
 * @param is InputStream on start of file. Otherwise signature can not be defined.
 * @return int id of signature or -1, if unknown signature was found. See SIGNATURE_ID_(type) constants to
 *      identify signature by its id.
 * @throws IOException in cases of read errors.
 */
public static int getSignatureIdFromHeader(InputStream is) throws IOException {
    // read signature from head of source and compare with known signatures
    int signatureId = -1;
    int sigCount = SIGNATURES.length;
    int[] byteArray = new int[MAX_SIGNATURE_LENGTH];
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < MAX_SIGNATURE_LENGTH; i++) {
        byteArray[i] = is.read();
        builder.append(Integer.toHexString(byteArray[i]));
    }
    if (DEBUG) {
        Log.d(TAG, "head bytes=" + builder.toString());
    }
    for (int i = 0; i < MAX_SIGNATURE_LENGTH; i++) {

        // check each bytes with known signatures
        int bytes = byteArray[i];
        int lastSigId = -1;
        int coincidences = 0;

        for (int j = 0; j < sigCount; j++) {
            int[] sig = SIGNATURES[j];

            if (DEBUG) {
                Log.d(TAG, "compare" + i + ": " + Integer.toHexString(bytes) + " with " + sig[i]);
            }
            if (bytes == sig[i]) {
                lastSigId = j;
                coincidences++;
            }
        }

        // signature is unknown
        if (coincidences == 0) {
            break;
        }
        // if first bytes of signature is known we check signature for full coincidence
        if (coincidences == 1) {
            int[] sig = SIGNATURES[lastSigId];
            int sigLength = sig.length;
            boolean isSigKnown = true;
            for (; i < MAX_SIGNATURE_LENGTH && i < sigLength; i++) {
                bytes = byteArray[i];
                if (bytes != sig[i]) {
                    isSigKnown = false;
                    break;
                }
            }
            if (isSigKnown) {
                signatureId = lastSigId;
            }
            break;
        }
    }
    return signatureId;
}

signatureIdé um índice de assinatura na matriz de assinaturas. Por exemplo,

private static final int[] SIGNATURE_PNG = hexStringToIntArray("89504E470D0A1A0A");
private static final int[] SIGNATURE_JPEG = hexStringToIntArray("FFD8FF");
private static final int[] SIGNATURE_GIF = hexStringToIntArray("474946");

public static final int SIGNATURE_ID_JPEG = 0;
public static final int SIGNATURE_ID_PNG = 1;
public static final int SIGNATURE_ID_GIF = 2;
private static final int[][] SIGNATURES = new int[3][];

static {
    SIGNATURES[SIGNATURE_ID_JPEG] = SIGNATURE_JPEG;
    SIGNATURES[SIGNATURE_ID_PNG] = SIGNATURE_PNG;
    SIGNATURES[SIGNATURE_ID_GIF] = SIGNATURE_GIF;
}

Agora eu tenho o tipo de arquivo, mesmo que o URI do arquivo não tenha. Em seguida, recebo o tipo mime por tipo de arquivo. Se você não souber qual tipo de mímica obter, poderá encontrar o apropriado nesta tabela .

Funciona para muitos tipos de arquivos. Mas para o vídeo não funciona, porque você precisa de um codec de vídeo conhecido para obter um tipo de mímica. Para obter o tipo MIME do vídeo, uso o MediaMetadataRetriever .

Sergei Vasilenko
fonte
4

Tentei usar métodos padrão para determinar o tipo de mímica, mas não consigo reter a extensão do arquivo usando MimeTypeMap.getFileExtensionFromUrl(uri.getPath()). Este método me devolveu uma string vazia. Então, eu fiz uma solução não trivial para manter a extensão do arquivo.

Aqui está o método retornando a extensão do arquivo:

private String getExtension(String fileName){
    char[] arrayOfFilename = fileName.toCharArray();
    for(int i = arrayOfFilename.length-1; i > 0; i--){
        if(arrayOfFilename[i] == '.'){
            return fileName.substring(i+1, fileName.length());
        }
    }
    return "";
}

E, mantendo a extensão do arquivo, é possível obter o tipo mime como abaixo:

public String getMimeType(File file) {
    String mimeType = "";
    String extension = getExtension(file.getName());
    if (MimeTypeMap.getSingleton().hasExtension(extension)) {
        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return mimeType;
}
I. Shvedenenko
fonte
Cara, isso acertou todas as respostas postadas aqui sobre esse problema! Eu tive o mesmo problema com todas as classes do Legacy. O problema foi o mesmo que você mencionou, MimeTypeMap.getFileExtensionFromUrlretornou uma string vazia para os nomes de arquivos que possuem caracteres inválidos conforme a implementação interna de a PatternMatcher. Isso funcionou para mim completamente! Adorei, sem problemas até agora!
sud007
@EU. Shvedenenko String extension = file.getName().split("\\.")[1]também teria funcionado, eliminando o método getExtension ().
Shahood ul Hassan
Mas o problema é: e se uma extensão errada for usada durante a criação do arquivo? A extensão deve ser o único juiz do tipo MIME?
Shahood ul Hassan
2

MimeTypeMappode não reconhecer algumas extensões de arquivo como flv, mpeg, 3gpp, cpp. Então, você precisa pensar em como expandir o MimeTypeMap para manter seu código. Aqui está um exemplo.

http://grepcode.com/file/repo1.maven.org/maven2/com.google.okhttp/okhttp/20120626/libcore/net/MimeUtils.java#MimeUtils

Além disso, aqui está uma lista completa dos tipos de mímica

http: //www.sitepoint.com/web-foundations/mime-types-complete-list/

Min Thant Htoo
fonte
2

Para Xamarin Android (da resposta da @ HoaLe acima)

public String getMimeType(Uri uri) {
    String mimeType = null;
    if (uri.Scheme.Equals(ContentResolver.SchemeContent))
    {
        ContentResolver cr = Application.Context.ContentResolver;
        mimeType = cr.GetType(uri);
    }
    else
    {
        String fileExtension = MimeTypeMap.GetFileExtensionFromUrl(uri.ToString());
        mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(
        fileExtension.ToLower());
    }
    return mimeType;
}
Curiosidade
fonte
1
get file object....
File file = new File(filePath);

then....pass as a parameter to...

getMimeType(file);

...here is 


public String getMimeType(File file) {
        String mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString()).toLowerCase());
        if (mimetype == null) {
            return "*/*";
        }
        return mimetype;///return the mimeType
    }
Nilesh Panchal
fonte
1

Enquanto estiver no ativo / arquivo (observe que faltam alguns casos no MimeTypeMap).

private String getMimeType(String path) {
    if (null == path) return "*/*";

    String extension = path;
    int lastDot = extension.lastIndexOf('.');
    if (lastDot != -1) {
        extension = extension.substring(lastDot + 1);
    }

    // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
    extension = extension.toLowerCase(Locale.getDefault());
    if (extension.equals("3ga")) {
        return "audio/3gpp";
    } else if (extension.equals("js")) {
        return "text/javascript";
    } else if (extension.equals("woff")) {
        return "application/x-font-woff";
    } else {
        // TODO
        // anyting missing from the map (http://www.sitepoint.com/web-foundations/mime-types-complete-list/)
        // reference: http://grepcode.com/file/repo1.maven.org/maven2/com.google.okhttp/okhttp/20120626/libcore/net/MimeUtils.java#MimeUtils
    }

    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}

Enquanto usa o ContentResolver

contentResolver.getType(uri)

Enquanto a solicitação http / https

    try {
        HttpURLConnection conn = httpClient.open(new URL(uri.toString()));
        conn.setDoInput(false);
        conn.setRequestMethod("HEAD");
        return conn.getHeaderField("Content-Type");
    } catch (IOException e) {
    }
WCG
fonte
1
// This will return the mimeType. 
// for eg. xyz.png it will return image/png. 
// here uri is the file that we were picked using intent from ext/internal storage.
private String getMimeType(Uri uri) {
   // This class provides applications access to the content model.  
   ContentResolver contentResolver = getContentResolver();

   // getType(Uri url)-Return the MIME type of the given content URL. 
   return contentResolver.getType(uri);
}
iamdhariot
fonte
Por favor, forneça alguma explicação. Isso ajudará o leitor inicial a adaptar seu código e outros leitores a obter o máximo valor da sua resposta.
Aurélien B
obrigado pela sua resposta. Eu edito com explicação.
precisa saber é o seguinte
1

Eu enfrentei um problema semelhante. Até agora eu sei que o resultado pode ser diferente para nomes diferentes, então finalmente cheguei a esta solução.

public String getMimeType(String filePath) {
    String type = null;
    String extension = null;
    int i = filePath.lastIndexOf('.');
    if (i > 0)
        extension = filePath.substring(i+1);
    if (extension != null)
        type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    return type;
}  
Ashish Sahu
fonte
0

A solução acima retornou nulo no caso do arquivo .rar, usando URLConnection.guessContentTypeFromName (url) trabalhado nesse caso.

Luis Barragan
fonte
0

mime do arquivo local:

String url = file.getAbsolutePath();
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mime = fileNameMap.getContentTypeFor("file://"+url);
Flinbor
fonte
0

você tem várias opções para obter a extensão do arquivo: como: 1- String filename = uri.getLastPathSegment();veja este link

2-você pode usar esse código também

 filePath .substring(filePath.lastIndexOf(".")+1);

mas isso não é bom dia. 3 - se você tiver um URI de arquivo, use este código

String[] projection = { MediaStore.MediaColumns.DATA,
MediaStore.MediaColumns.MIME_TYPE };

4-se você tiver URL, use este código:

 public static String getMimeType(String url) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) { 


  type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }

return type;
}

aproveite seu código :)

John smith
fonte
0
// new processing the mime type out of Uri which may return null in some cases
String mimeType = getContentResolver().getType(uri);
// old processing the mime type out of path using the extension part if new way returned null
if (mimeType == null){mimeType URLConnection.guessContentTypeFromName(path);}
YEH
fonte
0
public static String getFileType(Uri file)
{
    try
    {
        if (file.getScheme().equals(ContentResolver.SCHEME_CONTENT))
            return subStringFromLastMark(SystemMaster.getContentResolver().getType(file), "/");
        else
            return MimeTypeMap.getFileExtensionFromUrl(file.toString()).toLowerCase();
    }
    catch(Exception e)
    {
        return null;
    }
}

public static String getMimeType(Uri file)
{
    try
    {
        return MimeTypeMap.getSingleton().getMimeTypeFromExtension(getFileType(file));
    }
    catch(Exception e)
    {
        return null;
    }
}

public static String subStringFromLastMark(String str,String mark)
{
    int l = str.lastIndexOf(mark);
    int end = str.length();
    if(l == -1)
        return str;

    return str.substring(l + 1, end);
}
Ali Bagheri
fonte
0

Também retornou valor nulo no meu caminho de caso foi

/ armazenamento / emulado / 0 / Música / 01 - Ghost on the Dance Floor.mp3

como contornar o uso

val url = inUrl.replace ("", "")

então método parece

@JvmStatic
    fun getMimeType(inUrl: String?): String {
        if (inUrl == null) return ""

        val url = inUrl.replace(" ","")
        var type: String? = null

        val extension = MimeTypeMap.getFileExtensionFromUrl(url)
        if (extension != null) {
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase())
        }

        if(type ==null){
            val cR = WifiTalkie.getApplicationContext().contentResolver
            type = cR.getType(Uri.parse(url))
        }

        if (type == null) {
            type = "*/*" // fallback method_type. You might set it to */*
        }
        return type
    }

como resultado, ele retorna resultado de sucesso:

audio / mpeg

Espero que ajude alguém

Serg Burlaka
fonte
0

Nenhuma das respostas aqui é perfeita. Aqui está uma resposta que combina os melhores elementos de todas as principais respostas:

public final class FileUtil {

    // By default, Android doesn't provide support for JSON
    public static final String MIME_TYPE_JSON = "application/json";

    @Nullable
    public static String getMimeType(@NonNull Context context, @NonNull Uri uri) {

        String mimeType = null;
        if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            ContentResolver cr = context.getContentResolver();
            mimeType = cr.getType(uri);
        } else {
            String fileExtension = getExtension(uri.toString());

            if(fileExtension == null){
                return null;
            }

            mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                    fileExtension.toLowerCase());

            if(mimeType == null){
                // Handle the misc file extensions
                return handleMiscFileExtensions(fileExtension);
            }
        }
        return mimeType;
    }

    @Nullable
    private static String getExtension(@Nullable String fileName){

        if(fileName == null || TextUtils.isEmpty(fileName)){
            return null;
        }

        char[] arrayOfFilename = fileName.toCharArray();
        for(int i = arrayOfFilename.length-1; i > 0; i--){
            if(arrayOfFilename[i] == '.'){
                return fileName.substring(i+1, fileName.length());
            }
        }
        return null;
    }

    @Nullable
    private static String handleMiscFileExtensions(@NonNull String extension){

        if(extension.equals("json")){
            return MIME_TYPE_JSON;
        }
        else{
            return null;
        }
    }
}
Manish Kumar Sharma
fonte
0
Intent myIntent = new Intent(android.content.Intent.ACTION_VIEW);
                        File file = new File(filePatch); 
                        Uri uris = Uri.fromFile(file);
                        String mimetype = null;
                        if 
(uris.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
                            ContentResolver cr = 
getApplicationContext().getContentResolver();
                            mimetype = cr.getType(uris);
                        } else {
                            String fileExtension = 
MimeTypeMap.getFileExtensionFromUrl(uris.toString());
mimetype =  MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension.toLowerCase());
                        }
Роман Зыков
fonte
0

Não sei por que MimeTypeMap.getFileExtensionFromUrl()tem problemas com spaces e com outros caracteres, isso retorna "", mas acabei de escrever esse método para alterar o nome do arquivo para um nome admissível. Está apenas brincando com Strings. No entanto, isso meio que funciona. Através do método, os spaces existentes no nome do arquivo são transformados em um caractere desejável (que, aqui, é "x") via replaceAll(" ", "x")e outros caracteres inadequados são transformados em um caractere adequado URLEncoder. portanto, o uso (de acordo com os códigos apresentados na pergunta e na resposta selecionada) deve ser algo parecido getMimeType(reviseUrl(url)).

private String reviseUrl(String url) {

        String revisedUrl = "";
        int fileNameBeginning = url.lastIndexOf("/");
        int fileNameEnding = url.lastIndexOf(".");

        String cutFileNameFromUrl = url.substring(fileNameBeginning + 1, fileNameEnding).replaceAll(" ", "x");

        revisedUrl = url.
                substring(0, fileNameBeginning + 1) +
                java.net.URLEncoder.encode(cutFileNameFromUrl) +
                url.substring(fileNameEnding, url.length());

        return revisedUrl;
    }
elyar abad
fonte