获取 Uri Android 的真实路径
Posted
技术标签:
【中文标题】获取 Uri Android 的真实路径【英文标题】:Get Real Path For Uri Android 【发布时间】:2013-07-06 22:25:23 【问题描述】:我正在开发VideoPlayer
。我将启动意图的URI
转换为字符串,它给了我content://media/external.....
。但我需要找到真正的路径。
例如: /storage/extSdcard....
。
我该怎么做?
如果需要,这是我的代码:
videoURI = getIntent().getData();
vv.setVideoURI(videoURI);
videoName = videoURI.toString();
tvTitle.setText(videoName);
【问题讨论】:
【参考方案1】:使用此代码。这适用于所有 android 版本。这是经过测试的代码。这支持所有设备
public static String getPathFromUri(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];
// TODO handle non-primary volumes
// 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;
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())
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
finally
if (cursor != null)
cursor.close();
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());
/**
* @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());
【讨论】:
当DocumentsContract
本身仅在 API 级别 19 KitKat 之后可用时,这如何在所有 Android 版本上运行? developer.android.com/reference/android/provider/…
应该已经提到了原答案:***.com/a/27271131/1567541
@SANJAYGUPTA getPathFromUri() 将为外部 sdcard 文件返回 null。有什么解决方案吗??
如果存储是存储卡会怎样?如果在 Android L 中使用此方法,非主 get 为 null
它不能在 android 7 上运行。停止并出现此错误:列 '_data' 不存在【参考方案2】:
您可以将此代码用于选定的视频路径。
Uri uri = data.getData();
String[] filePathColumn = MediaStore.Images.Media.DATA;
Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
if(cursor.moveToFirst())
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String yourRealPath = cursor.getString(columnIndex);
else
//boooo, cursor doesn't have rows ...
cursor.close();
您可以参考以下链接寻求帮助。
Get filename and path from URI from mediastore
最新的文件提供程序 (API 29):
请点击链接:
博客:https://blogs.datanapps.com/media-picker Github:https://github.com/datanapps/MediaPicker
我希望你会成功。
【讨论】:
试试这个可能对你有帮助。否则我明天会更新我的ans。 journaldev.com/23219/… @PriyankaSingh 请尝试此链接,希望它对您有所帮助。 github.com/datanapps/MediaPicker【参考方案3】:在 Kotlin 中通过使用这个函数我们可以从 URI 中获取真实路径:
这里是getRealPathFromURI
的代码
fun getRealPathFromURI(context: Context, uri: Uri): String?
when
// DocumentProvider
DocumentsContract.isDocumentUri(context, uri) ->
when
// ExternalStorageProvider
isExternalStorageDocument(uri) ->
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true))
if (split.size > 1)
Environment.getExternalStorageDirectory().toString() + "/" + split[1]
else
Environment.getExternalStorageDirectory().toString() + "/"
// This is for checking SD Card
else
"storage" + "/" + docId.replace(":", "/")
isDownloadsDocument(uri) ->
val fileName = getFilePath(context, uri)
if (fileName != null)
return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
var id = DocumentsContract.getDocumentId(uri)
if (id.startsWith("raw:"))
id = id.replaceFirst("raw:".toRegex(), "")
val file = File(id)
if (file.exists()) return id
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
isMediaDocument(uri) ->
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":").toTypedArray()
val type = split[0]
var contentUri: Uri? = null
when (type)
"image" ->
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" ->
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" ->
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
"content".equals(uri.scheme, ignoreCase = true) ->
// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)
"file".equals(uri.scheme, ignoreCase = true) ->
return uri.path
return null
fun getDataColumn(context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?): String?
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(
column
)
try
if (uri == null) return null
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs,
null)
if (cursor != null && cursor.moveToFirst())
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
finally
cursor?.close()
return null
fun getFilePath(context: Context, uri: Uri?): String?
var cursor: Cursor? = null
val projection = arrayOf(
MediaStore.MediaColumns.DISPLAY_NAME
)
try
if (uri == null) return null
cursor = context.contentResolver.query(uri, projection, null, null,
null)
if (cursor != null && cursor.moveToFirst())
val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
return cursor.getString(index)
finally
cursor?.close()
return null
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
fun isExternalStorageDocument(uri: Uri): Boolean
return "com.android.externalstorage.documents" == uri.authority
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
fun isDownloadsDocument(uri: Uri): Boolean
return "com.android.providers.downloads.documents" == uri.authority
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
fun isMediaDocument(uri: Uri): Boolean
return "com.android.providers.media.documents" == uri.authority
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
fun isGooglePhotosUri(uri: Uri): Boolean
return "com.google.android.apps.photos.content" == uri.authority
在您的活动或片段中获取绕过 URI 到 getRealPathFromURI
函数的真实路径:
val fileRealPath = getRealPathFromURI(context!!, fileURI) ?: ""
【讨论】:
你好,在我的例子中,它进入 isDownloadDocument 路径,但 _id 是 msf:24,而不是 raw: & 不是数字。你能帮忙吗? @SanskarDahiya 如果id.startsWith("msf:")
***.com/a/62154537/2462531 试试这个方法
您好,我已经检查过了,但是内存有问题。因此,从 Andorid 文档中创建一些解决方案: if (isAndroid10 && id.startsWith("msf:")) final String[] split = id.split(":");最终字符串选择 = "_id=?"; final String[] selectionArgs = new String[] split[1] ;返回 getDataColumn(context, MediaStore.Downloads.EXTERNAL_CONTENT_URI, selection, selectionArgs); 【参考方案4】:
这是我以前用过的东西:
public String getRealPathFromURI (Uri contentUri)
String path = null;
String[] proj = MediaStore.MediaColumns.DATA ;
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if (cursor.moveToFirst())
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
path = cursor.getString(column_index);
cursor.close();
return path;
【讨论】:
光标为空。 这适用于媒体内容(来自媒体内容提供商),但不适用于存储访问框架文件。 @PriyankaSingh 你已经接受了一个答案。如果您已经走得更远了,现在遇到了稍微不同的问题,请发布一个新的具体问题 @KenWolf 接受的答案不适用于所有版本。【参考方案5】:大多数答案不适用于图库和相机图像。这对我有用。
public static String getPath(final Context context, final Uri uri)
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
Log.i("URI",uri+"");
String result = uri+"";
// DocumentProvider
// if (isKitKat && DocumentsContract.isDocumentUri(context, uri))
if (isKitKat && (result.contains("media.documents")))
String[] ary = result.split("/");
int length = ary.length;
String imgary = ary[length-1];
final String[] dat = imgary.split("%3A");
final String docId = dat[1];
final String type = dat[0];
Uri contentUri = null;
if ("image".equals(type))
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
else if ("video".equals(type))
else if ("audio".equals(type))
final String selection = "_id=?";
final String[] selectionArgs = new String[]
dat[1]
;
return getDataColumn(context, contentUri, selection, selectionArgs);
else if ("content".equalsIgnoreCase(uri.getScheme()))
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
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())
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
return null;
【讨论】:
【参考方案6】:试试这个:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data)
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 picturePath = cursor.getString(columnIndex);
cursor.close();
System.out.println("picturePath +"+ picturePath ); //path of sdcard
【讨论】:
【参考方案7】:在这里我从 onActivityResult() 获取 uri
Uri selectedImageURI = data.getData();
String realPath = getRealPathFromURI(selectedImageURI);
1) 在片段中你可以像这样使用函数..
private String getRealPathFromURI(Uri contentURI)
String filePath;
Cursor cursor = getActivity().getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null)
filePath = contentURI.getPath();
else
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
filePath = cursor.getString(idx);
cursor.close();
return filePath;
2) 你可以使用这样的功能。
private String getRealPathFromURI(Uri contentURI)
String filePath;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null)
filePath = contentURI.getPath();
else
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
filePath = cursor.getString(idx);
cursor.close();
return filePath;
【讨论】:
【参考方案8】:这里是如何通过 MediaStore 从 Uri 获取文件的真实路径::
private 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);
catch (Exception e)
Log.e(TAG, "getRealPathFromURI Exception : " + e.toString());
return "";
finally
if (cursor != null)
cursor.close();
【讨论】:
这不适用于 Android 10 或更高版本,因为无法再访问DATA
。它在早期版本的 Android 上不可靠。
这是否适用于其他文件类型,例如音频?正如@CommonsWare 所说,DATA
已被弃用
MediaStore.Images.Media.DATA 已弃用【参考方案9】:
这样称呼
Uri selectedImageURI = data.getData(); //where data is intent return by onActivityResult
imageFile = new File(getRealPathFromURI(selectedImageURI));
以及获取路径的代码..
private String getRealPathFromURI(Uri contentURI)
String result = null;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null)
// Source is Dropbox or other similar local file path
result = contentURI.getPath();
else
if(cursor.moveToFirst())
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
return result;
【讨论】:
java.lang.IllegalStateException: 无法从 CursorWindow 读取第 0 行 col -1。确保在从光标访问数据之前正确初始化光标。【参考方案10】:我找到了更优雅的解决方案:
Uri file_uri = Uri.parse(videoURI); // parse to Uri if your videoURI is string
String real_path = file_uri.getPath(); // will return real file path
【讨论】:
【参考方案11】:对于 Kotlin 人来说,这段代码对我有用
fun getPath(context: Context, uri: Uri): String?
val isKitKatorAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
// DocumentProvider
if (isKitKatorAbove && DocumentsContract.isDocumentUri(context, uri))
// ExternalStorageProvider
if (isExternalStorageDocument(uri))
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true))
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
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(":".toRegex()).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
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.getContentResolver().query(uri!!, projection, selection, selectionArgs,null)
if (cursor != null && cursor.moveToFirst())
val column_index: Int = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
finally
if (cursor != null) cursor.close()
return null
fun isExternalStorageDocument(uri: Uri): Boolean
return "com.android.externalstorage.documents" == uri.authority
fun isDownloadsDocument(uri: Uri): Boolean
return "com.android.providers.downloads.documents" == uri.authority
fun isMediaDocument(uri: Uri): Boolean
return "com.android.providers.media.documents" == uri.authority
您可以在 utils 类中添加这些方法
【讨论】:
【参考方案12】:我试图解决这个问题 2/3 天,但我找到的所有可能的解决方案都没有帮助。我不断收到空游标和类似错误。
我需要文件路径的原因是为了获取 Exif 数据,以便我可以以正确的方向显示图像。 (见A final answer on how to get Exif data from URI)
我找到了这个开源项目-
https://github.com/ArthurHub/Android-Image-Cropper/blob/master/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapUtils.java
有一种方法可以从 InputStream 中获取 Exif 数据,这解决了我的问题 -
ExifInterface ei = null;
try
InputStream is = context.getContentResolver().openInputStream(uri);
if (is != null)
ei = new ExifInterface(is);
is.close();
catch (Exception ignored)
我知道这不是直接回答问题,但由于我通过尝试解决这个问题找到了这个帖子,我认为我的回答可能对其他人有所帮助。
【讨论】:
【参考方案13】:package com.satya.filemangerdemo.common;
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.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
public class FileUtils
private static Uri contentUri = null;
/**
* 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.<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.
*/
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri)
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
String selection = null;
String[] selectionArgs = null;
// 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];
String fullPath = getPathFromExtSD(split);
if (fullPath != "")
return fullPath;
else
return null;
// DownloadsProvider
else if (isDownloadsDocument(uri))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
final String id;
Cursor cursor = null;
try
cursor = context.getContentResolver().query(uri, new String[]MediaStore.MediaColumns.DISPLAY_NAME, null, null, null);
if (cursor != null && cursor.moveToFirst())
String fileName = cursor.getString(0);
String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
if (!TextUtils.isEmpty(path))
return path;
finally
if (cursor != null)
cursor.close();
id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id))
if (id.startsWith("raw:"))
return id.replaceFirst("raw:", "");
String[] contentUriPrefixesToTry = new String[]
"content://downloads/public_downloads",
"content://downloads/my_downloads"
;
for (String contentUriPrefix : contentUriPrefixesToTry)
try
final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
/* final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));*/
return getDataColumn(context, contentUri, null, null);
catch (NumberFormatException e)
//In Android 8 and Android P the id is not a number
return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
else
final String id = DocumentsContract.getDocumentId(uri);
final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
if (id.startsWith("raw:"))
return id.replaceFirst("raw:", "");
try
contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
catch (NumberFormatException e)
e.printStackTrace();
if (contentUri != null)
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;
selection = "_id=?";
selectionArgs = new String[]split[1];
return getDataColumn(context, contentUri, selection,
selectionArgs);
else if (isGoogleDriveUri(uri))
return getDriveFilePath(uri, context);
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme()))
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
if (isGoogleDriveUri(uri))
return getDriveFilePath(uri, context);
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N)
// return getFilePathFromURI(context,uri);
return getMediaFilePathForN(uri, context);
// return getRealPathFromURI(context,uri);
else
return getDataColumn(context, uri, null, null);
// File
else if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
return null;
/**
* Check if a file exists on device
*
* @param filePath The absolute file path
*/
private static boolean fileExists(String filePath)
File file = new File(filePath);
return file.exists();
/**
* Get full file path from external storage
*
* @param pathData The storage type and the relative path
*/
private static String getPathFromExtSD(String[] pathData)
final String type = pathData[0];
final String relativePath = "/" + pathData[1];
String fullPath = "";
// on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
// something like "71F8-2C0A", some kind of unique id per storage
// don't know any API that can get the root path of that storage based on its id.
//
// so no "primary" type, but let the check here for other devices
if ("primary".equalsIgnoreCase(type))
fullPath = Environment.getExternalStorageDirectory() + relativePath;
if (fileExists(fullPath))
return fullPath;
// Environment.isExternalStorageRemovable() is `true` for external and internal storage
// so we cannot relay on it.
//
// instead, for each possible path, check if file exists
// we'll start with secondary storage as this could be our (physically) removable sd card
fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
if (fileExists(fullPath))
return fullPath;
fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
if (fileExists(fullPath))
return fullPath;
return fullPath;
private static String getDriveFilePath(Uri uri, Context context)
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1)
outputStream.write(buffers, 0, read);
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
catch (Exception e)
Log.e("Exception", e.getMessage());
return file.getPath();
private static String getMediaFilePathForN(Uri uri, Context context)
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1)
outputStream.write(buffers, 0, read);
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
catch (Exception e)
Log.e("Exception", e.getMessage());
return file.getPath();
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
finally
if (cursor != null)
cursor.close();
return null;
/**
* @param uri - The Uri to check.
* @return - Whether the Uri authority is ExternalStorageProvider.
*/
private 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.
*/
private 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.
*/
private 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.
*/
private static boolean isGooglePhotosUri(Uri uri)
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Drive.
*/
private static boolean isGoogleDriveUri(Uri uri)
return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
【讨论】:
以上代码在 android 所有设备以及所有类型的文件路径都可以在内部和外部打开,谷歌驱动器,gallery 等。请注意,请记住在 android 清单中添加文件提供程序。 它在来自设备外部存储的文件的情况下提供 NPE,uriString
为 content://media/external/file...
。我已经修复了它以获取 pdf 文档。【参考方案14】:
适用于 Android 的 Real Path Utility 类,适用于所有 API
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 androidx.loader.content.CursorLoader;
public class RealPathUtil
public static String getRealPath(Context context, Uri fileUri)
String realPath;
// SDK < API11
if (Build.VERSION.SDK_INT < 11)
realPath = RealPathUtil.getRealPathFromURI_BelowAPI11(context, fileUri);
// SDK >= 11 && SDK < 19
else if (Build.VERSION.SDK_INT < 19)
realPath = RealPathUtil.getRealPathFromURI_API11to18(context, fileUri);
// SDK > 19 (Android 4.4) and up
else
realPath = RealPathUtil.getRealPathFromURI_API19(context, fileUri);
return realPath;
@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri)
String[] proj = MediaStore.Images.Media.DATA;
String result = null;
CursorLoader cursorLoader = new CursorLoader(context, contentUri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
if (cursor != null)
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
cursor.close();
return result;
public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri)
String[] proj = MediaStore.Images.Media.DATA;
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = 0;
String result = "";
if (cursor != null)
column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
cursor.close();
return result;
return result;
/**
* 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 context.
* @param uri The Uri to query.
* @author paulburke
*/
@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(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];
// TODO handle non-primary volumes
// 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;
/**
* 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.
*/
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())
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
finally
if (cursor != null)
cursor.close();
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());
/**
* @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());
【讨论】:
您好,在我的情况下,它进入 isDownloadDocument 路径,但 _id 是 msf:24,而不是原始:& 不是数字。因此在使用 Long.valueOf 时会抛出错误,您能帮忙吗?【参考方案15】:我在 Android 10 中遇到了同样的问题,
因为我的文件 URI 包含 msf:
格式。
大多数解决方案都说将文件复制到缓存路径中,然后使用该路径。
因此,这里是获取路径的解决方案,无需复制。
if (isAndroid10 && id.startsWith("msf:"))
final String[] split = id.split(":");
final String selection = "_id=?";
final String[] selectionArgs = new String[] split[1] ;
return getDataColumn(context, MediaStore.Downloads.EXTERNAL_CONTENT_URI, selection, selectionArgs);
尝试实现这一点。
MediaStore.Downloads.EXTERNAL_CONTENT_URI -- ONLY PRESENT FROM ANDROID 10
【讨论】:
这行不通。 您好,由于我不是 Android 开发人员,这适用于我的应用程序。这就是我在此处发布此解决方案的原因。以上是关于获取 Uri Android 的真实路径的主要内容,如果未能解决你的问题,请参考以下文章
从URI获取真实路径,Android KitKat新的存储访问框架[重复]
java 从URI获取真实路径。字体:https://stackoverflow.com/questions/2789276/android-get-real-path-by-uri-getpath