假设我有一个完整的文件路径:(/sdcard/tlogo.png)。我想知道它的mime类型。

我为它创建了一个函数

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

但当我调用它时,它返回null。

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

当前回答

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

其他回答

有时Jeb和Jens的答案不工作并返回null。在这种情况下,我使用跟随解决方案。文件头通常包含类型签名。我阅读了它,并与已知的签名列表进行了比较。

/**
 *
 * @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是签名数组中签名的索引。例如,

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

现在我有了文件类型,即使文件的URI没有。接下来我得到mime类型的文件类型。如果你不知道要获取哪种mime类型,你可以在这个表中找到proper。

它适用于许多文件类型。但是对于视频,它不起作用,因为你需要知道视频编解码器来获得mime类型。为了获得视频的mime类型,我使用mediametadatareretrieve。

对于Xamarin Android(来自@HoaLe的回答)

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

首先,你应该考虑调用MimeTypeMap#getMimeTypeFromExtension(),就像这样:

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

EDIT

我为此创建了一个小型库。 但是底层代码几乎是一样的。

它在GitHub上可用

MimeMagic-Android

2020年9月

使用芬兰湾的科特林

fun File.getMimeType(context: Context): String? {
    if (this.isDirectory) {
        return null
    }

    fun fallbackMimeType(uri: Uri): String? {
        return if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
            context.contentResolver.getType(uri)
        } else {
            val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
            MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase(Locale.getDefault()))
        }
    }

    fun catchUrlMimeType(): String? {
        val uri = Uri.fromFile(this)

        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val path = Paths.get(uri.toString())
            try {
                Files.probeContentType(path) ?: fallbackMimeType(uri)
            } catch (ignored: IOException) {
                fallbackMimeType(uri)
            }
        } else {
            fallbackMimeType(uri)
        }
    }

    val stream = this.inputStream()
    return try {
        URLConnection.guessContentTypeFromStream(stream) ?: catchUrlMimeType()
    } catch (ignored: IOException) {
        catchUrlMimeType()
    } finally {
        stream.close()
    }
}

这似乎是最好的选择,因为它结合了前面的答案。

首先,它尝试使用URLConnection获取类型。guessContentTypeFromStream,但如果这个失败或返回null,它会尝试在Android O和以上使用mimetype

java.nio.file.Files
java.nio.file.Paths

否则,如果Android版本低于O或方法失败,它将使用ContentResolver和MimeTypeMap返回类型

我尝试使用标准方法来确定mime类型,但我不能使用MimeTypeMap.getFileExtensionFromUrl(uri.getPath())保留文件扩展名。这个方法返回一个空字符串。所以我做了一个重要的解决方案来保留文件扩展名。

下面是返回文件扩展名的方法:

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

并且保留了文件扩展名,可以获得如下所示的mime类型:

public String getMimeType(File file) {
    String mimeType = "";
    String extension = getExtension(file.getName());
    if (MimeTypeMap.getSingleton().hasExtension(extension)) {
        mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
    }
    return mimeType;
}