¿Cómo determinar el tipo de archivo MIME en Android?

176

Supongamos que tengo una ruta completa de archivo como: (/ sdcard / tlogo.png). Quiero saber su tipo mimo.

Creé una función para ello

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

pero cuando lo llamo, devuelve nulo.

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

Respuestas:

323

En primer lugar, debe considerar llamar MimeTypeMap#getMimeTypeFromExtension(), así:

// 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
fuente
44
gracias trabajo para mí y otra solución de mi problema es: String getMimeType (String, contexto contextual) {String extensionion = path.substring (path.lastIndexOf (".")); Cadena mimeTypeMap = MimeTypeMap.getFileExtensionFromUrl (extensión); Cadena mimeType = MimeTypeMap.getSingleton () .getMimeTypeFromExtension (mimeTypeMap); return mimeType;}
Sushant Bhatnagar
13
¿Y si el archivo no tiene la buena extensión? una persona puede hacer un .mp3 y contiene texto
throrin19
2
Entonces necesitaría abrir el archivo y verificar el número mágico (dependiendo del formato de c) en la entrada; esto, sin embargo, también supone que la persona que renombra los archivos txt a mp3 no solo escribió ID3en el comienzo de su texto para meterse contigo aún más.
Jens
1
Si el archivo tiene una extensión desconocida. ¿El método vuelve */*?
3
Si tiene una ruta de archivo como / storage / emulated / 0 / Download / images (4) .jpg y solicita mimetype, devuelve nulo.
Kalaiselvan
165

Detecta el tipo mime de cualquier archivo

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
fuente
55
Esta debería ser la respuesta correcta. toLowerCase()Hizo el truco.
Rajat Saxena
1
Esta es, con mucho, la mejor respuesta, pero falla miserablemente si el nombre del archivo tiene un carácter especial, ¡en mi caso, un apostrophe! P.ej. nombre de archivo = Don't go baby.mp3. El PatternMatcherinterior MimeTypeMap.getFileExtensionFromUrl()no puede manejar el nombre del archivo y devuelve una cadena vacía; ¡null resulta ser la cadena mimetype!
sud007
Hay una solución similar pero libre de errores a continuación por I. ShvedenenkoWorked para los problemas que he señalado anteriormente. Pero esta respuesta fue un puntero en la dirección correcta.
sud007
este código devuelve un valor nulo con String "/ storage / emulated / 0 / dcim / screenshots / screenshot_20190319-123828_ubl digital app.jpg".
Abdul
@Abdul Es porque esa ruta no tiene un esquema Uri. Debería comenzar con file://o content://.
HB.
33

La solución MimeTypeMap anterior devuelve nulo en mi uso. Esto funciona y es más fácil:

Uri uri = Uri.fromFile(file);
ContentResolver cR = context.getContentResolver();
String mime = cR.getType(uri);
Jeb
fuente
19
Este método también puede devolver nulo.
Señor Smith
Parece que puede devolver nulo o no, según el URI. Ningún cuerpo parece saber por qué ;-(
Thomas Decaux
10
Si se selecciona el medio de la galería de Android, se devuelve TYPE. Si se selecciona del Administrador de archivos, se devuelve un valor nulo.
Rahul Rastogi
Puedo confirmar positivamente lo que dijo Rahul, solo lo probé y tiene razón
Chris
En algunos dispositivos, si selecciono la imagen de la galería, también está volviendo nulo
Ghanshyam Nayma
21

Versión optimizada de la respuesta de Jens con seguridad nula y tipo de respaldo.

@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 () solo funciona con minúsculas !


Actualización (19.03.2018)

Bonificación: los métodos anteriores como una función de extensión de Kotlin menos detallada :

fun File.getMimeType(fallback: String = "image/*"): String {
    return MimeTypeMap.getFileExtensionFromUrl(toString())
            ?.run { MimeTypeMap.getSingleton().getMimeTypeFromExtension(toLowerCase()) }
            ?: fallback // You might set it to */*
}
Tobias
fuente
Esto funcionó. aunque demasiado detallado para mi gusto.
filthy_wizard
Por supuesto, esto puede ser escrito de una manera más corta. Con Kotlin probablemente solo dos o tres líneas, sin embargo, el zorro estaba en la parte nula de seguridad toLoverCase.
Tobias
@filthy_wizard, agregó una versión optimizada solo para ti ;-)
Tobias
En cuanto a mí, usar el método getPath () en lugar de toString () es más claro, y solo la ruta usa la sintaxis de acceso a la propiedad 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
fuente
1
¡Funciona perfecto para mí! Pero, ¿qué hay de usar FilenameUtils.getExetension (ruta) para obtener la extensión del archivo?
Peter
7

Preste mucha atención a la solución anterior de umerk44 . invoca y es CASO SENSIBLE. Pasé una tarde en esto y luego eché un vistazo más de cerca: volveré si lo pasas "JPG", mientras que devolverá "image / jpeg" si lo pasas "jpg".getMimeTypeFromExtensionguessMimeTypeTypeFromExtensiongetMimeTypeFromExtensionNULL

Mike Kogan
fuente
5

Aquí está la solución que utilicé en mi aplicación de 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
fuente
1
url? Mucha url no tiene extensión. Por ejemplo, esta página no tiene extensión. Para url, debe usar una nueva URL (url) .openConnection (). GetRequestProperty ("Content-type");
barwnikk
5

A veces las respuestas de Jeb y Jens no funcionan y devuelven nulas. En este caso, uso la solución Follow. El encabezado del archivo generalmente contiene firma de tipo. Lo leí y lo comparé con las conocidas en la lista de firmas .

/**
 *
 * @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;
}

signatureIdes un índice de firma en un conjunto de firmas. Por ejemplo,

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

Ahora tengo el tipo de archivo incluso si el URI del archivo no lo tiene. A continuación obtengo el tipo mime por tipo de archivo. Si no sabe qué tipo de mimo obtener, puede encontrar el adecuado en esta tabla .

Funciona para muchos tipos de archivos. Pero para el video no funciona, porque necesita un códec de video conocido para obtener un tipo mime. Para obtener el tipo mime de video, uso MediaMetadataRetriever .

Sergei Vasilenko
fuente
4

Traté de usar métodos estándar para determinar el tipo mime, pero no puedo retener la extensión de archivo usando MimeTypeMap.getFileExtensionFromUrl(uri.getPath()). Este método me devolvió una cadena vacía. Así que hice una solución no trivial para retener la extensión del archivo.

Aquí está el método que devuelve la extensión del archivo:

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

Y habiendo conservado la extensión del archivo, es posible obtener el tipo mime como se muestra a continuación:

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
fuente
Hombre, esto clavó todas las respuestas publicadas aquí sobre este problema! Tuve el mismo problema con todas las clases de Legacy. El problema era el mismo que mencionó, MimeTypeMap.getFileExtensionFromUrldevolvió una cadena vacía para los nombres de archivo que tienen caracteres no válidos según la implementación interna de a PatternMatcher. ¡Esto funcionó para mí por completo! Me encantó, no hay problemas hasta ahora!
sud007
@YO. Shvedenenko String extension = file.getName().split("\\.")[1]también habría funcionado, eliminando así el método getExtension ().
Shahood ul Hassan
Pero la cuestión es, ¿qué pasa si se usa una extensión incorrecta al crear el archivo? ¿Debería la extensión ser el único juez del tipo mime?
Shahood ul Hassan
2

Para Xamarin Android (De la respuesta de @ HoaLe arriba)

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;
}
Curiosidad
fuente
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
fuente
1

Mientras que desde el activo / archivo (Tenga en cuenta que faltan algunos casos del 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);
}

Mientras usa ContentResolver

contentResolver.getType(uri)

Mientras que la solicitud 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
fuente
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
fuente
Por favor proporcione alguna explicación. Ayudará al lector inicial a adaptar su código y a otros lectores para obtener el mayor valor de su respuesta.
Aurélien B
Gracias por su respuesta. Lo edito con explicación.
iamdhariot
1

Me enfrenté a un problema similar. Hasta ahora sé que el resultado puede ser diferente para diferentes nombres, así que finalmente llegué a esta solución.

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
fuente
0

La solución anterior devolvió un valor nulo en el caso de un archivo .rar, utilizando URLConnection.guessContentTypeFromName (url) funcionó en este caso.

Luis Barragán
fuente
0

mimo del archivo local:

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

tiene varias opciones para obtener la extensión del archivo: como: 1- String filename = uri.getLastPathSegment();vea este enlace

2-puedes usar este código también

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

pero esto no es bueno 3-si tiene URI de archivo, entonces use este Código

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

4-si tienes URL entonces usa 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;
}

disfruta tu código :)

John Smith
fuente
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);}
Si
fuente
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
fuente
0

También ha devuelto un valor nulo en mi ruta de caso fue

/ almacenamiento / emulado / 0 / Música / 01 - Fantasma en la pista de baile.mp3

como trabajo alrededor del uso

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

así se ve el método

@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, devuelve el resultado de éxito:

audio / mpeg

Espero que ayude a alguien

Serg Burlaka
fuente
0

Ninguna de las respuestas aquí son perfectas. Aquí hay una respuesta que combina los mejores elementos de todas las respuestas principales:

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
fuente
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());
                        }
Роман Зыков
fuente
0

No sé por qué MimeTypeMap.getFileExtensionFromUrl()tiene problemas con spacesy algunos otros caracteres, eso regresa "", pero acabo de escribir este método para cambiar el nombre del archivo a uno admitible. Es solo jugar con Strings. Sin embargo, funciona un poco. A través del método, los spaces existentes en el nombre del archivo se convierten en un carácter deseable (que, aquí, es "x") replaceAll(" ", "x")y otros caracteres no adecuados se convierten en uno adecuado URLEncoder. Por lo tanto, el uso (de acuerdo con los códigos presentados en la pregunta y la respuesta seleccionada) debería ser similar 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
fuente