這個問題糾結了我很長時間,終於有了比較好的解決方案。目前已知適配全部的機型,有問題就留言吧。javascript
public void OpenFile(View view) {
// 指定類型
String[] mimeTypes = {"*/*"};
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
StringBuilder mimeTypesStr = new StringBuilder();
for (String mimeType : mimeTypes) {
mimeTypesStr.append(mimeType).append("|");
}
intent.setType(mimeTypesStr.substring(0, mimeTypesStr.length() - 1));
startActivityForResult(Intent.createChooser(intent, "ChooseFile"), REQUEST_FILE_CODE);
}
複製代碼
其中mimeTypes
是指定文件的類型,好比圖片,好比Excel,即便設置了該屬性,在某些機型上沒有效果,因此在選擇文件後還須要判斷格式是否正確。html
爲了你們嫌麻煩,我把類型舉例放在了文章末尾,方便你們進行查詢。java
final int REQUEST_FILE_CODE = 1000;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_FILE_CODE && resultCode == RESULT_OK) {
Uri uri = data.getData();
Log.d(TAG, "uri:" + uri);
//String filePath = PickUtils.getPath(this, uri);
//textView.setText(filePath);
}
super.onActivityResult(requestCode, resultCode, data);
}
複製代碼
重點來了,咱們能夠很輕鬆的拿到Uri
, 可是轉absolute path
在不一樣的機型卻遇到了奇奇怪怪的問題,至今沒有徹底弄明白。android
大概的意思就是有些機型轉path時會失敗,好比在華爲10.0的機型上,經過下載內容
中打開Download
的文件就會失敗,場景是本來的documentid
能夠轉爲long型,但它變成了這個樣子msf:123
,致使轉換失敗。api
有不少人都存在這個問題,好比這個地址:stackoverflow.com/questions/5…數組
解決方法:在轉換絕對路徑失敗的狀況,將文件拷貝到本身的app的緩存目錄下,而後返回路徑。 代碼在文章末尾。瀏覽器
咱們能夠輕鬆的拿到Uri以後,實際上在不轉絕對路徑的狀況下,用Uri已經能夠作不少事情了,好比獲取文件類型、好比獲取文件的byte[]、獲取文件名 等等。緩存
類型對應
中去對照。/**
* 獲取文件的類型。
* @param context 上下文
* @param uri uri
* @return
*/
public static String getFormatByUri(@NonNull Context context, @NonNull Uri uri) {
String type = context.getContentResolver().getType(uri);
if (TextUtils.isEmpty(type)) return null;
return type;
}
複製代碼
/**
* 根據uri獲取 byte[]
* @param context
* @param uri
* @return
* @throws IOException
*/
public static byte[] getBytesByUri(Context context, Uri uri) throws IOException {
InputStream iStream = context.getContentResolver().openInputStream(uri);
if (iStream == null) return null;
return getBytes(iStream);
}
private static byte[] getBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
複製代碼
/**
* 獲取文件名
* @param uri uri
* @return
*/
public String getFileNameByUri(Uri uri) {
String filename = "";
Cursor returnCursor = getContentResolver().query(uri, null,
null, null, null);
if (returnCursor != null) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
returnCursor.close();
}
return filename;
}
複製代碼
固然,這個完美的工具類仍是提供給你們。出處我不記得了,我稍微改了一點,目前用下來很是完美。 只是在轉path不成功的狀況下,會拷貝文件放到應用的緩存目錄,你們須要注意下清理緩存的時機。markdown
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by pangw on 2018/5/23.
*/
public class PickUtils {
public static final String DOCUMENTS_DIR = "documents";
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id != null && id.startsWith("raw:")) {
return id.substring(4);
}
String[] contentUriPrefixesToTry = new String[]{
"content://downloads/public_downloads",
"content://downloads/my_downloads"
};
for (String contentUriPrefix : contentUriPrefixesToTry) {
try {
// note: id 可能爲字符串,如在華爲10.0系統上,選擇文件後id爲:"msf:254",致使轉Long異常
Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.parseLong(id));
String path = getDataColumn(context, contentUri, null, null);
if (path != null && !path.equals("")) {
return path;
}
} catch (Exception e) {
}
}
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
String fileName = getFileName(context, uri);
File cacheDir = getDocumentCacheDir(context);
File file = generateFileName(fileName, cacheDir);
String destinationPath = null;
if (file != null) {
destinationPath = file.getAbsolutePath();
saveFileFromUri(context, uri, destinationPath);
}
return destinationPath;
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
String path = getDataColumn(context, uri, null, null);
if (path != null && !path.equals("")) return path;
// path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
String fileName = getFileName(context, uri);
File cacheDir = getDocumentCacheDir(context);
File file = generateFileName(fileName, cacheDir);
String destinationPath = null;
if (file != null) {
destinationPath = file.getAbsolutePath();
saveFileFromUri(context, uri, destinationPath);
}
return destinationPath;
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
String path = "";
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
path = cursor.getString(column_index);
return path;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return path;
}
public static String getFileName(@NonNull Context context, Uri uri) {
String mimeType = context.getContentResolver().getType(uri);
String filename = null;
if (mimeType == null && context != null) {
String path = getPath(context, uri);
if (path == null) {
filename = getName(uri.toString());
} else {
File file = new File(path);
filename = file.getName();
}
} else {
Cursor returnCursor = context.getContentResolver().query(uri, null,
null, null, null);
if (returnCursor != null) {
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
filename = returnCursor.getString(nameIndex);
returnCursor.close();
}
}
return filename;
}
public static String getName(String filename) {
if (filename == null) {
return null;
}
int index = filename.lastIndexOf('/');
return filename.substring(index + 1);
}
public static File getDocumentCacheDir(@NonNull Context context) {
Log.d("PickUtils", "getDocumentCacheDir");
File dir = new File(context.getCacheDir(), DOCUMENTS_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
return dir;
}
@Nullable
public static File generateFileName(@Nullable String name, File directory) {
if (name == null) {
return null;
}
File file = new File(directory, name);
if (file.exists()) {
String fileName = name;
String extension = "";
int dotIndex = name.lastIndexOf('.');
if (dotIndex > 0) {
fileName = name.substring(0, dotIndex);
extension = name.substring(dotIndex);
}
int index = 0;
while (file.exists()) {
index++;
name = fileName + '(' + index + ')' + extension;
file = new File(directory, name);
}
}
try {
if (!file.createNewFile()) {
return null;
}
} catch (IOException e) {
return null;
}
return file;
}
private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
InputStream is = null;
BufferedOutputStream bos = null;
try {
is = context.getContentResolver().openInputStream(uri);
bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
byte[] buf = new byte[1024];
is.read(buf);
do {
bos.write(buf);
} while (is.read(buf) != -1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) is.close();
if (bos != null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製代碼
private final String[][] MIME_MapTable={
//{後綴名,MIME類型}
{".3gp", "video/3gpp"},
{".apk", "application/vnd.android.package-archive"},
{".asf", "video/x-ms-asf"},
{".avi", "video/x-msvideo"},
{".bin", "application/octet-stream"},
{".bmp", "image/bmp"},
{".c", "text/plain"},
{".class", "application/octet-stream"},
{".conf", "text/plain"},
{".cpp", "text/plain"},
{".doc", "application/msword"},
{".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
{".xls", "application/vnd.ms-excel"},
{".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
{".exe", "application/octet-stream"},
{".gif", "image/gif"},
{".gtar", "application/x-gtar"},
{".gz", "application/x-gzip"},
{".h", "text/plain"},
{".htm", "text/html"},
{".html", "text/html"},
{".jar", "application/java-archive"},
{".java", "text/plain"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "application/x-javascript"},
{".log", "text/plain"},
{".m3u", "audio/x-mpegurl"},
{".m4a", "audio/mp4a-latm"},
{".m4b", "audio/mp4a-latm"},
{".m4p", "audio/mp4a-latm"},
{".m4u", "video/vnd.mpegurl"},
{".m4v", "video/x-m4v"},
{".mov", "video/quicktime"},
{".mp2", "audio/x-mpeg"},
{".mp3", "audio/x-mpeg"},
{".mp4", "video/mp4"},
{".mpc", "application/vnd.mpohun.certificate"},
{".mpe", "video/mpeg"},
{".mpeg", "video/mpeg"},
{".mpg", "video/mpeg"},
{".mpg4", "video/mp4"},
{".mpga", "audio/mpeg"},
{".msg", "application/vnd.ms-outlook"},
{".ogg", "audio/ogg"},
{".pdf", "application/pdf"},
{".png", "image/png"},
{".pps", "application/vnd.ms-powerpoint"},
{".ppt", "application/vnd.ms-powerpoint"},
{".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
{".prop", "text/plain"},
{".rc", "text/plain"},
{".rmvb", "audio/x-pn-realaudio"},
{".rtf", "application/rtf"},
{".sh", "text/plain"},
{".tar", "application/x-tar"},
{".tgz", "application/x-compressed"},
{".txt", "text/plain"},
{".wav", "audio/x-wav"},
{".wma", "audio/x-ms-wma"},
{".wmv", "audio/x-ms-wmv"},
{".wps", "application/vnd.ms-works"},
{".xml", "text/plain"},
{".z", "application/x-compress"},
{".zip", "application/x-zip-compressed"},
{"", "*/*"}
};
複製代碼