Android 選擇文件返回路徑怎麼就這麼難?

Android 選擇文件返回路徑怎麼就這麼難?

這個問題糾結了我很長時間,終於有了比較好的解決方案。目前已知適配全部的機型,有問題就留言吧。javascript

正確姿式來一遍

1. 打開系統自帶的文件瀏覽器並限制類型

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

2. 返回選擇的數據

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的緩存目錄下,而後返回路徑。 代碼在文章末尾。瀏覽器

3. 思考與拓展

咱們能夠輕鬆的拿到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;

}

複製代碼

4. URI 轉 Path

固然,這個完美的工具類仍是提供給你們。出處我不記得了,我稍微改了一點,目前用下來很是完美。 只是在轉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();

}

}

}

}

複製代碼

5. 類型對應

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

  {"", "*/*"}

  };

複製代碼
相關文章
相關標籤/搜索