如何确定在android文件的MIME类型?

假设我有一个完整的文件路径:(/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);
181731 次浏览

首先也是最重要的,你应该考虑调用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;
}

上面的MimeTypeMap解决方案在我的使用中返回null。这很有效,而且更简单:

Uri uri = Uri.fromFile(file);
ContentResolver cR = context.getContentResolver();
String mime = cR.getType(uri);

上面的解决方案在.rar文件的情况下返回null,使用URLConnection.guessContentTypeFromName(url)在这种情况下工作。

以下是我在我的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;
}
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解决方案getMimeTypeFromExtension调用guessMimeTypeTypeFromExtension并且区分大小写。我花了一个下午的时间,然后仔细研究了一下——如果你传递“JPG”,getMimeTypeFromExtension将返回NULL,而如果你传递“JPG”,它将返回“image/jpeg”。

MimeTypeMap可能无法识别一些文件扩展名,如flv,mpeg,3gpp,cpp。因此,您需要考虑如何扩展MimeTypeMap以维护代码。这里有这样一个例子。

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

< p> Plus,这里是一个完整的mime类型列表

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

有时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类型,我使用MediaMetadataRetriever

Mime从本地文件:

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

检测任何文件的mime类型

public String getMimeType(Uri uri) {
String mimeType = null;
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
ContentResolver cr = getAppContext().getContentResolver();
mimeType = cr.getType(uri);
} else {
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
.toString());
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
fileExtension.toLowerCase());
}
return mimeType;
}

你有多种选择来获得文件扩展名: 1-String filename = uri.getLastPathSegment(); see this 链接

2-你也可以使用这段代码

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

但这不是一个好方法。 3-如果你有文件的URI,那么使用这个代码

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

4-如果你有URL,那么使用下面的代码:

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




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


return type;
}

享受你的代码:)

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

而从资产/文件(注意,在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);
}

而使用ContentResolver

contentResolver.getType(uri)

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

我尝试使用标准方法来确定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;
}

延斯”的优化版本带有null-safety和fallback-type。

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

重要的: getFileExtensionFromUrl()只适用于小写字母!


更新(19.03.2018)

附加:上面的方法是一个不太详细的Kotlin扩展函数:

fun File.getMimeType(fallback: String = "image/*"): String {
return MimeTypeMap.getFileExtensionFromUrl(toString())
?.run { MimeTypeMap.getSingleton().getMimeTypeFromExtension(toLowerCase()) }
?: fallback // You might set it to */*
}

对于Xamarin的安卓(来自上面@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;
}
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);
}

也返回空值 在我的例子中,路径是

/storage/ emululated /0/Music/01 - Ghost on the Dance Floor.mp3

在工作中使用

val url = inUrl。替换(" "," ")

方法是这样的

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

结果返回成功结果:

音频/ mpeg

希望能对大家有所帮助

这里没有一个答案是完美的。以下是一个结合了所有热门答案的最佳元素的答案:

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

我也遇到过类似的问题。到目前为止,我知道不同的名字可能会有不同的结果,所以最终得出了这个解决方案。

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

我不知道为什么MimeTypeMap.getFileExtensionFromUrl()在__abc1和其他一些返回""的字符上有问题,但我刚刚写了这个方法来将文件名更改为一个可允许的名称。它只是在玩__abc3。然而,这是可行的。通过该方法,文件名中存在的__abc1将通过replaceAll(" ", "x")转换为理想字符(这里是"x"),而其他不合适的字符将通过URLEncoder转换为合适的字符。因此用法(根据问题中给出的代码和选择的答案)应该是类似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;
}

编辑

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

它在GitHub上可用

mimemmagic - 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返回类型

它适用于我和灵活的内容和文件

public static String getMimeType(Context context, Uri uri) {
String extension;


//Check uri format to avoid null
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
//If scheme is a content
final MimeTypeMap mime = MimeTypeMap.getSingleton();
extension = mime.getExtensionFromMimeType(context.getContentResolver().getType(uri));
} else {
//If scheme is a File
//This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());


}


return extension;
}

在kotlin中,这要简单得多。

解决方案1:

fun getMimeType(file: File): String? =
MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.extension)

方案二:(文件扩展名函数)

fun File.mimeType(): String? =
MimeTypeMap.getSingleton().getMimeTypeFromExtension(this.extension)