假设我有一个完整的文件路径:(/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);
有时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。
你有多种选择来获得文件扩展名:
字符串文件名= uri.getLastPathSegment();请看这个链接
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;
}
享受你的代码:)
而从资产/文件(注意,在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;
}
Jens的回答的优化版本与零安全和回退类型。
@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 */*
}
这里没有一个答案是完美的。以下是一个结合了所有热门答案的最佳元素的答案:
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;
}
}
}
I don't realize why MimeTypeMap.getFileExtensionFromUrl() has problems with spaces and some other characters, that returns "", but I just wrote this method to change the file name to an admit-able one. It's just playing with Strings. However, It kind of works. Through the method, the spaces existing in the file name is turned into a desirable character (which, here, is "x") via replaceAll(" ", "x") and other unsuitable characters are turned into a suitable one via URLEncoder. so the usage (according to the codes presented in the question and the selected answer) should be something like 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;
}
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返回类型