从 mediastore 的 URI 获取文件名和路径
Posted
技术标签:
【中文标题】从 mediastore 的 URI 获取文件名和路径【英文标题】:Get filename and path from URI from mediastore 【发布时间】:2011-03-25 00:21:01 【问题描述】:我有一个 onActivityResult
从媒体存储图像选择返回,我可以使用以下内容获取图像的 URI:
Uri selectedImage = data.getData();
将其转换为字符串会得到:
content://media/external/images/media/47
或者给一条路径:
/external/images/media/47
但是我似乎找不到将其转换为绝对路径的方法,因为我想将图像加载到位图中而不必将其复制到某处。我知道这可以使用 URI 和内容解析器来完成,但这似乎会在手机重启时中断,我猜 MediaStore
在重启之间不会保持其编号相同。
【问题讨论】:
gist.github.com/tatocaster/32aad15f6e0c50311626 API 19 及更高版本的解决方案在这里,***.com/a/51227392/9815519。希望这可以帮助你。 【参考方案1】:API 19 下使用此代码从 URI 获取文件路径:
public String getRealPathFromURI(Context context, Uri contentUri)
Cursor cursor = null;
try
String[] proj = MediaStore.Images.Media.DATA ;
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
【讨论】:
Drive 应用程序不适合我。 URI:content://com.google.android.apps.docs.files/exposed_content/tHV4PoDlSl1OAu3qtER7rQ%3D%3D%0A%3BG1D2s6GYCEX7Niqtuj%2F7Bwa71jRnlkCknibIU24b%2FO5BROqc0NMwnGsVaAIvxSTN%0A 正如 Christopher 指出的那样 - 4.4+ 不支持此问题,请参阅此问题了解更多信息:***.com/questions/20067508/… 不起作用。光标为空。而且我不在 Android 4.4+ 上,我在 4.1.2 上。 在 5 台设备上测试。对除 Android 4.1.2 之外的所有设备都给出 null。在所有较新的 Android 上都返回 null。 数据常量在 Android Q(10) 中已弃用【参考方案2】:只是对第一个答案的简单更新:mActivity.managedQuery()
现在已弃用。我已经用新方法更新了代码。
private String getRealPathFromURI(Uri contentUri)
String[] proj = MediaStore.Images.Media.DATA ;
CursorLoader loader = new CursorLoader(mContext, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
android dev source
【讨论】:
@dextor:这对我不起作用。当我在文件浏览器中单击文件时,它可以工作,但是当我单击电子邮件附件时,我仍然得到content://...
的东西。我在这里尝试了所有建议,但没有运气。知道为什么吗?
@Luis me too 我也遇到了同样的问题
@dextor 你需要关闭光标。
你能帮忙吗:***.com/questions/27103529/…
@dextor 我试过这个解决方案它没有用,可能同时发生了一些变化。然而,Paul Burke 从这个问题***.com/questions/20067508/… 的解决方案奏效了。【参考方案3】:
奥利奥
Uri uri = data.getData();
File file = new File(uri.getPath());//create path from uri
final String[] split = file.getPath().split(":");//split the path.
filePath = split[1];//assign it to a string(your choice).
对于奥利奥以下的所有版本,我制作了这个从uri获取真实路径的方法
@SuppressLint("NewApi")
public static String getFilePath(Context context, Uri uri) throws URISyntaxException
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri))
if (isExternalStorageDocument(uri))
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
else if (isDownloadsDocument(uri))
final String id = DocumentsContract.getDocumentId(uri);
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
else if (isMediaDocument(uri))
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("image".equals(type))
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
else if ("video".equals(type))
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
else if ("audio".equals(type))
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
selection = "_id=?";
selectionArgs = new String[]
split[1]
;
if ("content".equalsIgnoreCase(uri.getScheme()))
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
String[] projection =
MediaStore.Images.Media.DATA
;
Cursor cursor = null;
try
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst())
return cursor.getString(column_index);
catch (Exception e)
e.printStackTrace();
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
public static boolean isExternalStorageDocument(Uri uri)
return "com.android.externalstorage.documents".equals(uri.getAuthority());
public static boolean isDownloadsDocument(Uri uri)
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
public static boolean isMediaDocument(Uri uri)
return "com.android.providers.media.documents".equals(uri.getAuthority());
public static boolean isGooglePhotosUri(Uri uri)
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
【讨论】:
这是唯一可以在各种类型的 Uri 上无缝运行的版本 - 应该是最佳答案.. 如果用户没有从 SD 卡中选择文件,则此代码有效。如果用户从 SD 卡中选择了文件,则返回的路径例如是 /storage/emulated/0/filePath,即使文件位于 /storage/sdCard/filePath 好吧,您可以尝试一些库,例如 android url 的材料选择器:github.com/nbsp-team/MaterialFilePicker 这可以让您更接近解决方案,如果您有任何解决方案,请在下面发布..跨度> 也不起作用:java.lang.UnsupportedOperationException: Unsupported Uri content://com.android.externalstorage.documents/tree/primary%3ADCIM%2FCamera...为什么 android 团队如此成功困难 这不适用于 Android 9.0 (Pie) 中下载的 pdf 文件。【参考方案4】:不要尝试在文件系统中查找 uri,在数据库中查找内容会很慢。
您可以通过向工厂提供输入流来从 uri 中获取位图,就像向工厂提供文件一样:
InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
【讨论】:
其实这是唯一正确的回应。没有人真正关心文件名。我们需要的是内容。实际文件可能位于应用程序的私有文件夹、互联网、sqlite 中,或者是纯虚拟的并动态生成。 所问的具体问题是文件名和路径。是的,OP 正在寻求从文件中派生位图,但对于每个寻找路径的人来说,情况并非如此。有时我们需要实际的文件内容。 @durilka,例如:如果文件是视频并且您想要缩略图,则可以使用 String 类型的路径调用函数“ThumbnailUtils.createVideoThumbnail”,不接受任何提示输入流。 我会首先检查视频内容提供商是否提供缩略图和元数据。 Android 的全部内容是“如果有人已经这样做了,就不要自己实现它”。每一个雄心勃勃的应用程序都试图创建自己的照片捕捉功能,这让我感到非常震惊。 您刚刚引入了导致 OutOfMemory 错误的路径【参考方案5】:这是我从 URI (如 file://... 和 content://... )获取文件名的示例。它不仅适用于 Android MediaStore,而且适用于 EzExplorer 等第三方应用程序。
public static String getFileNameByUri(Context context, Uri uri)
String fileName="unknown";//default fileName
Uri filePathUri = uri;
if (uri.getScheme().toString().compareTo("content")==0)
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
filePathUri = Uri.parse(cursor.getString(column_index));
fileName = filePathUri.getLastPathSegment().toString();
else if (uri.getScheme().compareTo("file")==0)
fileName = filePathUri.getLastPathSegment().toString();
else
fileName = fileName+"_"+filePathUri.getLastPathSegment();
return fileName;
【讨论】:
这可以在 file:// 和 content:// URI 之间转换,反之亦然吗?我尝试在我的项目中包含代码,但它说 ApplicationObject 无法解析。 ApplicationObject有问题,能给我一些代码吗? 哦,没关系,别担心,我找到了其他一些有效的示例代码,干杯。 这不愧是最佳答案,比较全面,解决了我遇到的一个问题。 列“_data”不存在【参考方案6】:现有的好答案,其中一些我曾经自己想出:
我必须从 URI 中获取路径并从路径中获取 URI,Google 很难分辨出两者之间的区别,因此对于遇到相同问题的任何人(例如,从视频的 MediaStore
获取缩略图)您已经拥有其物理位置)。前者:
/**
* Gets the corresponding path to a file from the given content:// URI
* @param selectedVideoUri The content:// URI to find the file path from
* @param contentResolver The content resolver to use to perform the query.
* @return the file path as a string
*/
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver)
String filePath;
String[] filePathColumn = MediaColumns.DATA;
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
后者(我用于视频,但也可用于音频或文件或其他类型的存储内容,方法是用 MediaStore.Audio(等)代替 MediaStore.Video):
/**
* Gets the MediaStore video ID of a given file on external storage
* @param filePath The path (on external storage) of the file to resolve the ID of
* @param contentResolver The content resolver to use to perform the query.
* @return the video ID as a long
*/
private long getVideoIdFromFilePath(String filePath,
ContentResolver contentResolver)
long videoId;
Log.d(TAG,"Loading file " + filePath);
// This returns us content://media/external/videos/media (or something like that)
// I pass in "external" because that's the MediaStore's name for the external
// storage on my device (the other possibility is "internal")
Uri videosUri = MediaStore.Video.Media.getContentUri("external");
Log.d(TAG,"videosUri = " + videosUri.toString());
String[] projection = MediaStore.Video.VideoColumns._ID;
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] filePath , null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
videoId = cursor.getLong(columnIndex);
Log.d(TAG,"Video ID is " + videoId);
cursor.close();
return videoId;
基本上,MediaStore
的 DATA
列(或您要查询的任何子部分)存储文件路径,因此您可以使用您所知道的来查找该 DATA
字段,或者使用该字段可查找您想要的任何其他内容。
然后我进一步使用上面的Scheme
来确定如何处理我的数据:
private boolean getSelectedVideo(Intent imageReturnedIntent, boolean fromData)
Uri selectedVideoUri;
//Selected image returned from another activity
// A parameter I pass myself to know whether or not I'm being "shared via" or
// whether I'm working internally to my app (fromData = working internally)
if(fromData)
selectedVideoUri = imageReturnedIntent.getData();
else
//Selected image returned from SEND intent
// which I register to receive in my manifest
// (so people can "share via" my app)
selectedVideoUri = (Uri)getIntent().getExtras().get(Intent.EXTRA_STREAM);
Log.d(TAG,"SelectedVideoUri = " + selectedVideoUri);
String filePath;
String scheme = selectedVideoUri.getScheme();
ContentResolver contentResolver = getContentResolver();
long videoId;
// If we are sent file://something or content://org.openintents.filemanager/mimetype/something...
if(scheme.equals("file") || (scheme.equals("content") && selectedVideoUri.getEncodedAuthority().equals("org.openintents.filemanager")))
// Get the path
filePath = selectedVideoUri.getPath();
// Trim the path if necessary
// openintents filemanager returns content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.mp4
if(filePath.startsWith("/mimetype/"))
String trimmedFilePath = filePath.substring("/mimetype/".length());
filePath = trimmedFilePath.substring(trimmedFilePath.indexOf("/"));
// Get the video ID from the path
videoId = getVideoIdFromFilePath(filePath, contentResolver);
else if(scheme.equals("content"))
// If we are given another content:// URI, look it up in the media provider
videoId = Long.valueOf(selectedVideoUri.getLastPathSegment());
filePath = getFilePathFromContentUri(selectedVideoUri, contentResolver);
else
Log.d(TAG,"Failed to load URI " + selectedVideoUri.toString());
return false;
return true;
【讨论】:
通过使用你从 URI 中获取路径的代码,我可以在 React Native 中返回用于保存在 CameraRoll 中的路径,谢谢【参考方案7】:在所有情况下,这些答案都不适合我。我不得不直接去谷歌的文档https://developer.android.com/guide/topics/providers/document-provider.html就这个话题找到了这个有用的方法:
private Bitmap getBitmapFromUri(Uri uri) throws IOException
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
您可以使用此位图在图像视图中显示它。
【讨论】:
但是,如果我们想要一个路径而不是位图,那该怎么办?【参考方案8】:现在情况很复杂,尤其是在 API 级别 29 Android Q 之后。
您必须在 manifest.xml 中 requestLegacyStorage
。
这就是你应该如何从内容 Uri 中获取文件名
public static String getNameFromContentUri(Context context, Uri contentUri)
Cursor returnCursor = context.getContentResolver().query(contentUri, null, null, null, null);
int nameColumnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
String fileName = returnCursor.getString(nameColumnIndex);
return fileName;
这就是您获取所有 android 版本的 Content Uri 完整路径的方式
JAVA
public static String getFullPathFromContentUri(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 ("com.android.externalstorage.documents".equals(uri.getAuthority()))
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];
//non-primary e.g sd card
else
if (Build.VERSION.SDK_INT > 20)
//getExternalMediaDirs() added in API 21
File extenal[] = context.getExternalMediaDirs();
for (File f : extenal)
filePath = f.getAbsolutePath();
if (filePath.contains(type))
int endIndex = filePath.indexOf("Android");
filePath = filePath.substring(0, endIndex) + split[1];
else
filePath = "/storage/" + type + "/" + split[1];
return filePath;
// DownloadsProvider
else if ("com.android.providers.downloads.documents".equals(uri.getAuthority()))
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
// MediaProvider
else if ("com.android.providers.media.documents".equals(uri.getAuthority()))
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]
;
Cursor cursor = null;
final String column = "_data";
final String[] projection =
column
;
try
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst())
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
return null;
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme()))
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs)
Cursor cursor = null;
final String column = "_data";
final String[] projection =
column
;
try
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst())
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
return null;
科特林
companion object
@JvmStatic
@SuppressLint("NewApi")
fun getPath(context: Context, uri: Uri): String?
val isKitKat: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri))
// ExternalStorageProvider
if (isExternalStorageDocument(uri))
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
return if ("primary".equals(type, ignoreCase = true))
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
else // non-primary volumes e.g sd card
var filePath = "non"
//getExternalMediaDirs() added in API 21
val extenal = context.externalMediaDirs
for (f in extenal)
filePath = f.absolutePath
if (filePath.contains(type))
val endIndex = filePath.indexOf("Android")
filePath = filePath.substring(0, endIndex) + split[1]
filePath
else if (isDownloadsDocument(uri))
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
else if (isMediaDocument(uri))
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type)
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
else if ("video" == type)
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
else if ("audio" == type)
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val selection = "_id=?"
val selectionArgs = arrayOf(
split[1]
)
return getDataColumn(context, contentUri, selection, selectionArgs)
else if ("content".equals(uri.scheme, ignoreCase = true))
return getDataColumn(context, uri, null, null)
else if ("file".equals(uri.scheme, ignoreCase = true))
return uri.path
return null
private fun getDataColumn(context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?): String?
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(
column
)
try
cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs,
null)
if (cursor != null && cursor.moveToFirst())
val column_index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
catch (e: java.lang.Exception)
finally
cursor?.close()
return null
private fun isExternalStorageDocument(uri: Uri): Boolean
return "com.android.externalstorage.documents" == uri.authority
private fun isDownloadsDocument(uri: Uri): Boolean
return "com.android.providers.downloads.documents" == uri.authority
private fun isMediaDocument(uri: Uri): Boolean
return "com.android.providers.media.documents" == uri.authority
【讨论】:
使用“_data”与使用“MediaStore.Images.Media.DATA”相同,从 api 29 中弃用。 已弃用,因为应用可能无权使用它,已授予权限的应用可以使用它。 我的意思是getDataColumn
正在使用已弃用的 _data
列,而您正在为每个 api 级别调用 getDataColumn
。【参考方案9】:
API 19 及更高版本,Uri 的图像文件路径 完美运行。我还检查了这个最新的 PIE API 28。
public String getImageFilePath(Uri uri)
String path = null, image_id = null;
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
image_id = cursor.getString(0);
image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
cursor.close();
Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]image_id, null);
if (cursor!=null)
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
【讨论】:
首先,你已经初始化了两次光标!其次,这段代码在这一行抛出CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
:path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
我正在使用 Oreo stock android,但由于某种原因它无法正常工作
如何从 URI 中获取 pdf 文件文件路径你能帮我吗
@HarshilPansare,你是如何让它在 Android Oreo 上运行的?我被困了2天。
@Mustansir :图像也不起作用。第二个查询不返回任何内容【参考方案10】:
对于过去的 Android Q,MediaStore.Images.Media.DATA 将不再可用时有什么办法吗?此字段在 Android Q 中已折旧:
此常量在 API 级别 29 中已弃用。 应用程序可能没有直接访问此路径的文件系统权限。应用应该使用 ContentResolver#openFileDescriptor(Uri, String) 来获取访问权限,而不是尝试直接打开此路径。
https://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#DATA
--- 已编辑
据我所知,对于过去的 Android Q,唯一的方法是中继 RELATIVE_PATH
此媒体项目在其被持久化的存储设备中的相对路径。例如,存储在 /storage/0000-0000/DCIM/Vacation/IMG1024.JPG 的项目的路径为 DCIM/Vacation/。
https://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#RELATIVE_PATH
【讨论】:
android Q 中的所有文件都有相对路径还是我们需要添加它们,比如如果文件已经存在于设备上,那么它的相对路径是否可用? @1234567 根据链接中的描述,如果您将其传递为null,则系统将正确设置它。如果文件已存在,则媒体扫描仪应添加该字段。 你需要 Android Q 作为目标 API 并且可能打开 Scoped storage【参考方案11】:试试这个从 Uri 获取图像文件路径
public void getImageFilePath(Context context, Uri uri)
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String image_id = cursor.getString(0);
image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]image_id, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
upLoadImageOrLogo(path);
【讨论】:
【参考方案12】:迁移到 KitKat 后遇到问题的解决方案:
“这将从MediaProvider、DownloadsProvider和ExternalStorageProvider获取文件路径,同时回退到非官方的ContentProvider方法”https://***.com/a/20559175/690777
【讨论】:
这似乎是完美的答案【参考方案13】:试试这个
不过,如果您遇到问题以获取真正的路径,您可以尝试我的答案。以上答案对我没有帮助。
说明:-该方法获取URI,然后根据API级别检查您的Android设备的API级别,它将生成Real路径。 生成真实路径方法的代码因API级别而异。
从URI获取真实路径的方法
@SuppressLint("ObsoleteSdkInt")
public String getPathFromURI(Uri uri)
String realPath="";
// SDK < API11
if (Build.VERSION.SDK_INT < 11)
String[] proj = MediaStore.Images.Media.DATA ;
@SuppressLint("Recycle") Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
int column_index = 0;
String result="";
if (cursor != null)
column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
realPath=cursor.getString(column_index);
// SDK >= 11 && SDK < 19
else if (Build.VERSION.SDK_INT < 19)
String[] proj = MediaStore.Images.Media.DATA ;
CursorLoader cursorLoader = new CursorLoader(this, uri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if(cursor != null)
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
realPath = cursor.getString(column_index);
// SDK > 19 (Android 4.4)
else
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = MediaStore.Images.Media.DATA ;
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[] id , null);
int columnIndex = 0;
if (cursor != null)
columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst())
realPath = cursor.getString(columnIndex);
cursor.close();
return realPath;
像这样使用这个方法
Log.e(TAG, "getRealPathFromURI: "+getPathFromURI(your_selected_uri) );
输出:-
04-06 12:39:46.993 6138-6138/com.app.qtm E/tag: getRealPathFromURI: /storage/emulated/0/Video/avengers_infinity_war_4k_8k-7680x4320.jpg
【讨论】:
我的物理设备 API 级别 25 使用命令String wholeID = DocumentsContract.getDocumentId(uri);
返回 FATAL EXCEPTION 我得到:java.lang.RuntimeException: Failure delivering result
在我的例子中,这个例子返回路径 null
兄弟!你真是个天才!上面的例子对我也不起作用,所以我最后一次尝试了你的代码,它起作用了!!!!!【参考方案14】:
从图库中获取图片后,只需将以下方法中的 URI 传递给 Android 4.4 (KitKat):
public String getPath(Uri contentUri) // Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = MediaStore.Images.Media.DATA ;
// Where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel,
new String[] id , null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst())
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
【讨论】:
这是唯一对我有用的。我想要画廊里的东西。您有以下 Kitkat 的工作方法吗? @sharma_kunai【参考方案15】:我已经这样做了:
Uri queryUri = MediaStore.Files.getContentUri("external");
String columnData = MediaStore.Files.FileColumns.DATA;
String columnSize = MediaStore.Files.FileColumns.SIZE;
String[] projectionData = MediaStore.Files.FileColumns.DATA;
String name = null;
String size = null;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if ((cursor != null)&&(cursor.getCount()>0))
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
name = cursor.getString(nameIndex);
size = cursor.getString(sizeIndex);
cursor.close();
if ((name!=null)&&(size!=null))
String selectionNS = columnData + " LIKE '%" + name + "' AND " +columnSize + "='" + size +"'";
Cursor cursorLike = getContentResolver().query(queryUri, projectionData, selectionNS, null, null);
if ((cursorLike != null)&&(cursorLike.getCount()>0))
cursorLike.moveToFirst();
int indexData = cursorLike.getColumnIndex(columnData);
if (cursorLike.getString(indexData) != null)
result = cursorLike.getString(indexData);
cursorLike.close();
return result;
【讨论】:
【参考方案16】:@PercyPercy 的略微修改版本 - 它不会抛出并且只是如果出现任何问题返回 null:
public String getPathFromMediaUri(Context context, Uri uri)
String result = null;
String[] projection = MediaStore.Images.Media.DATA ;
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
int col = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
if (col >= 0 && cursor.moveToFirst())
result = cursor.getString(col);
cursor.close();
return result;
【讨论】:
【参考方案17】:由于 managedQuery 已被弃用,您可以尝试:
CursorLoader cursorLoader = new CursorLoader(context, uri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
【讨论】:
【参考方案18】:在这里,我将向您展示如何创建一个浏览按钮,当您单击该按钮时,它将打开 SD 卡,您将选择一个文件,然后您将获得文件名和文件路径被选中的:
你会点击的按钮
browse.setOnClickListener(new OnClickListener()
public void onClick(View v)
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
Uri startDir = Uri.fromFile(new File("/sdcard"));
startActivityForResult(intent, PICK_REQUEST_CODE);
);
获取结果文件名和文件路径的函数
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
if (requestCode == PICK_REQUEST_CODE)
if (resultCode == RESULT_OK)
Uri uri = intent.getData();
if (uri.getScheme().toString().compareTo("content")==0)
Cursor cursor =getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
Uri filePathUri = Uri.parse(cursor.getString(column_index));
String file_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show();
【讨论】:
我遵循了这里的建议,但没有奏效。当我单击 K9 电子邮件客户端附件时,我会收到content://com.fsck.k9.attachmentprovider/34fc2cc9-aa46-45e9-9e3f-2f27f0457249/1/VIEW
。应用这里的方法后,我仍然得到相同的字符串,而不是正确的路径,即/mnt/sdcard/Android/data/com.fsck.k9/files/34fc2cc9-aa46-45e9-9e3f-2f27f0457249.db_att/1
。有什么线索吗?【参考方案19】:
public String getPath(Uri uri)
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]document_id, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
将文件 URI 转换为字符串文件路径的完美工作方法
【讨论】:
在某些手机(包括 nexus 和 oppo)的下载文件夹中获取图像时无法正常工作 @AliAzazAlam 请仔细检查日志,可能还有其他问题。顺便说一句,它应该可以工作,我也在模拟器和物理设备中对其进行了测试。【参考方案20】:这里是文件名
String[] projection = MediaStore.MediaColumns.DISPLAY_NAME;
Uri uri = data.getData();
String fileName = null;
ContentResolver cr = getActivity().getApplicationContext().getContentResolver();
Cursor metaCursor = cr.query(uri,
projection, null, null, null);
if (metaCursor != null)
try
if (metaCursor.moveToFirst())
fileName = metaCursor.getString(0);
finally
metaCursor.close();
【讨论】:
可能对操作没有太大帮助,因为他正在寻找绝对路径(不仅仅是文件名)......但它确实帮助我理解了这个过程。【参考方案21】:简单易行。您可以从 URI 中执行此操作,如下所示!
public void getContents(Uri uri)
Cursor vidCursor = getActivity.getContentResolver().query(uri, null, null,
null, null);
if (vidCursor.moveToFirst())
int column_index =
vidCursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
Uri filePathUri = Uri.parse(vidCursor .getString(column_index));
String video_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Log.i("TAG", video_name + "\b" file_path);
【讨论】:
【参考方案22】:此解决方案适用于所有情况:
在某些情况下,从 URL 获取路径太难了。那你为什么需要路径?将文件复制到其他地方?你不需要路径。
public void SavePhotoUri (Uri imageuri, String Filename)
File FilePath = context.getDir(Environment.DIRECTORY_PICTURES,Context.MODE_PRIVATE);
try
Bitmap selectedImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), imageuri);
String destinationImagePath = FilePath + "/" + Filename;
FileOutputStream destination = new FileOutputStream(destinationImagePath);
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, destination);
destination.close();
catch (Exception e)
Log.e("error", e.toString());
【讨论】:
【参考方案23】:我用一个衬里做到这一点:
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)
onActivityResult 中的内容如下:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_IMAGE_PICKER )
data?.data?.let imgUri: Uri ->
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, imgUri)
【讨论】:
由于某种原因,如果我使用三星图库应用选择图像,这种方法不起作用 很奇怪。我在三星 Galaxy S10 上进行开发。【参考方案24】:不幸的是,上面提到的答案都没有奏效。最后我成功了。
这会将您的 URI 转换为图像。
Uri selectedImage = data.getData();
String[] filePathColumn = MediaStore.Images.Media.DATA;
Cursor cursor = getContentResolver().query(
selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
下面是我用来选择图片的代码。
Intent intent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, SELECT_PICTURES);
【讨论】:
【参考方案25】:完美地为我工作来自这个post的固定代码:
public static String getRealPathImageFromUri(Uri uri)
String fileName =null;
if (uri.getScheme().equals("content"))
try (Cursor cursor = MyApplication.getInstance().getContentResolver().query(uri, null, null, null, null))
if (cursor.moveToFirst())
fileName = cursor.getString(cursor.getColumnIndexOrThrow(ediaStore.Images.Media.DATA));
catch (IllegalArgumentException e)
Log.e(mTag, "Get path failed", e);
return fileName;
【讨论】:
【参考方案26】:作为附加组件,如果您需要在尝试打开输入流之前查看文件是否存在,您可以使用 DocumentsContract。
(Kotlin 代码)
var iStream = null
if(DocumentsContract.isDocumentUri(context,myUri))
val pfd: ParcelFileDescriptor? = context.contentResolver.openFileDescriptor(
myUri, "r") ?: return null
iStream = ParcelFileDescriptor.AutoCloseInputStream(pfd)
【讨论】:
【参考方案27】:由于上述答案对我不起作用,以下是对我有用的解决方案:
适用于 >19 和
此方法涵盖了从uri获取filePath的所有情况
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The activity.
* @param uri The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri)
// DocumentProvider
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && 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];
else
Toast.makeText(context, "Could not get file path. Please try again", Toast.LENGTH_SHORT).show();
// DownloadsProvider
else if (isDownloadsDocument(uri))
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
// 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;
else
contentUri = MediaStore.Files.getContentUri("external");
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()))
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
【讨论】:
就我而言,它进入 isDownloadsDocument(uri) 检查。但是 URI 是 msf:12,因此无法获取路径。有人帮忙吗?【参考方案28】:要获取任何类型的文件路径,请使用:
/*
* Copyright (C) 2007-2008 OpenIntents.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yourpackage;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileFilter;
import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.List;
/**
* @author Peli
* @author paulburke (ipaulpro)
* @version 2013-12-11
*/
public class FileUtils
private FileUtils()
//private constructor to enforce Singleton pattern
/**
* TAG for log messages.
*/
static final String TAG = "FileUtils";
private static final boolean DEBUG = true; // Set to true to enable logging
public static final String MIME_TYPE_AUDIO = "audio/*";
public static final String MIME_TYPE_TEXT = "text/*";
public static final String MIME_TYPE_IMAGE = "image/*";
public static final String MIME_TYPE_VIDEO = "video/*";
public static final String MIME_TYPE_APP = "application/*";
public static final String HIDDEN_PREFIX = ".";
/**
* Gets the extension of a file name, like ".png" or ".jpg".
*
* @param uri
* @return Extension including the dot("."); "" if there is no extension;
* null if uri was null.
*/
public static String getExtension(String uri)
if (uri == null)
return null;
int dot = uri.lastIndexOf(".");
if (dot >= 0)
return uri.substring(dot);
else
// No extension.
return "";
/**
* @return Whether the URI is a local one.
*/
public static boolean isLocal(String url)
if (url != null && !url.startsWith("http://") && !url.startsWith("https://"))
return true;
return false;
/**
* @return True if Uri is a MediaStore Uri.
* @author paulburke
*/
public static boolean isMediaUri(Uri uri)
return "media".equalsIgnoreCase(uri.getAuthority());
/**
* Convert File into Uri.
*
* @param file
* @return uri
*/
public static Uri getUri(File file)
if (file != null)
return Uri.fromFile(file);
return null;
/**
* Returns the path only (without file name).
*
* @param file
* @return
*/
public static File getPathWithoutFilename(File file)
if (file != null)
if (file.isDirectory())
// no file to be split off. Return everything
return file;
else
String filename = file.getName();
String filepath = file.getAbsolutePath();
// Construct path without file name.
String pathwithoutname = filepath.substring(0,
filepath.length() - filename.length());
if (pathwithoutname.endsWith("/"))
pathwithoutname = pathwithoutname.substring(0, pathwithoutname.length() - 1);
return new File(pathwithoutname);
return null;
/**
* @return The MIME type for the given file.
*/
public static String getMimeType(File file)
String extension = getExtension(file.getName());
if (extension.length() > 0)
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
return "application/octet-stream";
/**
* @return The MIME type for the give Uri.
*/
public static String getMimeType(Context context, Uri uri)
File file = new File(getPath(context, uri));
return getMimeType(file);
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is @link LocalStorageProvider.
* @author paulburke
*/
public static boolean isLocalStorageDocument(Uri uri)
return LocalStorageProvider.AUTHORITY.equals(uri.getAuthority());
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
* @author paulburke
*/
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.
* @author paulburke
*/
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.
* @author paulburke
*/
public static boolean isMediaDocument(Uri uri)
return "com.android.providers.media.documents".equals(uri.getAuthority());
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri)
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
* @author paulburke
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs)
Cursor cursor = null;
final String column = "_data";
final String[] projection =
column
;
try
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst())
if (DEBUG)
DatabaseUtils.dumpCursor(cursor);
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
catch (Exception e)
e.printStackTrace();
finally
if (cursor != null)
cursor.close();
return null;
/**
* Get a file path from a Uri. This will quickGet the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.<br>
* <br>
* Callers should check whether the path is local before assuming it
* represents a local file.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
* @see #isLocal(String)
* @see #getFile(Context, Uri)
*/
public static String getPath(final Context context, final Uri uri)
if (DEBUG)
Log.d(TAG + " File -",
"Authority: " + uri.getAuthority() +
", Fragment: " + uri.getFragment() +
", Port: " + uri.getPort() +
", Query: " + uri.getQuery() +
", Scheme: " + uri.getScheme() +
", Host: " + uri.getHost() +
", Segments: " + uri.getPathSegments().toString()
);
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri))
// LocalStorageProvider
if (isLocalStorageDocument(uri))
// The path is the id
return DocumentsContract.getDocumentId(uri);
// ExternalStorageProvider
else 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];
//
return Environment.getExternalStorageDirectory() + "/" + split[1];
// TODO handle non-primary volumes
// DownloadsProvider
else if (isDownloadsDocument(uri))
try
final String id = DocumentsContract.getDocumentId(uri);
Log.d(TAG, "getPath: id= " + id);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
catch (Exception e)
e.printStackTrace();
List<String> segments = uri.getPathSegments();
if(segments.size() > 1)
String rawPath = segments.get(1);
if(!rawPath.startsWith("/"))
return rawPath.substring(rawPath.indexOf("/"));
else
return rawPath;
// 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()))
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
/**
* Convert Uri into File, if possible.
*
* @return file A local file that the Uri was pointing to, or null if the
* Uri is unsupported or pointed to a remote resource.
* @author paulburke
* @see #getPath(Context, Uri)
*/
public static File getFile(Context context, Uri uri)
if (uri != null)
String path = getPath(context, uri);
if (path != null && isLocal(path))
return new File(path);
return null;
/**
* Get the file size in a human-readable string.
*
* @param size
* @return
* @author paulburke
*/
public static String getReadableFileSize(int size)
final int BYTES_IN_KILOBYTES = 1024;
final DecimalFormat dec = new DecimalFormat("###.#");
final String KILOBYTES = " KB";
final String MEGABYTES = " MB";
final String GIGABYTES = " GB";
float fileSize = 0;
String suffix = KILOBYTES;
if (size > BYTES_IN_KILOBYTES)
fileSize = size / BYTES_IN_KILOBYTES;
if (fileSize > BYTES_IN_KILOBYTES)
fileSize = fileSize / BYTES_IN_KILOBYTES;
if (fileSize > BYTES_IN_KILOBYTES)
fileSize = fileSize / BYTES_IN_KILOBYTES;
suffix = GIGABYTES;
else
suffix = MEGABYTES;
return String.valueOf(dec.format(fileSize) + suffix);
/**
* Attempt to retrieve the thumbnail of given File from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param file
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, File file)
return getThumbnail(context, getUri(file), getMimeType(file));
/**
* Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param uri
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, Uri uri)
return getThumbnail(context, uri, getMimeType(context, uri));
/**
* Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param uri
* @param mimeType
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, Uri uri, String mimeType)
if (DEBUG)
Log.d(TAG, "Attempting to quickGet thumbnail");
if (!isMediaUri(uri))
Log.e(TAG, "You can only retrieve thumbnails for images and videos.");
return null;
Bitmap bm = null;
if (uri != null)
final ContentResolver resolver = context.getContentResolver();
Cursor cursor = null;
try
cursor = resolver.query(uri, null, null, null, null);
if (cursor.moveToFirst())
final int id = cursor.getInt(0);
if (DEBUG)
Log.d(TAG, "Got thumb ID: " + id);
if (mimeType.contains("video"))
bm = MediaStore.Video.Thumbnails.getThumbnail(
resolver,
id,
MediaStore.Video.Thumbnails.MINI_KIND,
null);
else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE))
bm = MediaStore.Images.Thumbnails.getThumbnail(
resolver,
id,
MediaStore.Images.Thumbnails.MINI_KIND,
null);
catch (Exception e)
if (DEBUG)
Log.e(TAG, "getThumbnail", e);
finally
if (cursor != null)
cursor.close();
return bm;
/**
* File and folder comparator. TODO Expose sorting option method
*
* @author paulburke
*/
public static Comparator<File> sComparator = new Comparator<File>()
@Override
public int compare(File f1, File f2)
// Sort alphabetically by lower case, which is much cleaner
return f1.getName().toLowerCase().compareTo(
f2.getName().toLowerCase());
;
/**
* File (not directories) filter.
*
* @author paulburke
*/
public static FileFilter sFileFilter = new FileFilter()
@Override
public boolean accept(File file)
final String fileName = file.getName();
// Return files only (not directories) and skip hidden files
return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
;
/**
* Folder (directories) filter.
*
* @author paulburke
*/
public static FileFilter sDirFilter = new FileFilter()
@Override
public boolean accept(File file)
final String fileName = file.getName();
// Return directories only and skip hidden directories
return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX);
;
/**
* Get the Intent for selecting content to be used in an Intent Chooser.
*
* @return The intent for opening a file with Intent.createChooser()
* @author paulburke
*/
public static Intent createGetContentIntent()
// Implicitly allow the user to select a particular kind of data
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// The MIME data type filter
intent.setType("*/*");
// Only return URIs that can be opened with ContentResolver
intent.addCategory(Intent.CATEGORY_OPENABLE);
return intent;
【讨论】:
终于,一个可行的方法! (从这段代码中我刚刚删除了 LocalStorageProvider)【参考方案29】:如果您的系统版本高于 19,这对我来说非常有用,希望这可以帮助您。
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri)
final boolean isOverKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isOverKitKat && 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);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
// 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()))
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
【讨论】:
【参考方案30】:获取 Uri 如下所示。
//* get cursor like normal
然后
while (cursor.moveToNext())
Uri uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
【讨论】:
以上是关于从 mediastore 的 URI 获取文件名和路径的主要内容,如果未能解决你的问题,请参考以下文章
我可以从android中的uri获取图像文件的宽度和高度吗?