获取Android Uri的真实路径

39

我正在开发一个VideoPlayer。我将启动的意图的URI转换为字符串,它给了我content://media/external.....。但我需要获取真正的路径。

例如: /storage/extSdcard....

我该怎么做?

这是我的代码,如果需要:

videoURI = getIntent().getData();
vv.setVideoURI(videoURI);

videoName = videoURI.toString();

tvTitle.setText(videoName);
17个回答

53

使用此代码。这适用于所有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());
}

6
DocumentsContract自API 19 KitKat版本才可用,那么它是如何在所有Android版本上运行的呢? - Hendra Anggrian
3
应该提到原始答案:https://dev59.com/-WIj5IYBdhLWcg3wsnCn#27271131 - Hendra Anggrian
12
对于外部SD卡文件,getPathFromUri()将返回null。 有任何解决方法吗? - KJEjava48
2
如果存储是内存卡,使用此方法在Android L中,非主要的将会得到null。 - Md Imran Choudhury
3
当从非主下载文件夹中下载时,应用程序崩溃:java.lang.RuntimeException: 在将结果 ResultInfo{who=null, request=9999, result=-1, data=Intent { dat=content://com.android.providers.downloads.documents/document/msf:11063 flg=0x1 }} 传递给活动 {com.alquran.tafhimul_quran/com.alquran.tafhimul_quran.OnlineSavingFiles} 时失败:java.lang.NumberFormatException: 输入字符串 "msf:11063" 格式不正确。 - Noor Hossain
显示剩余5条评论

17

使用此函数,我们可以从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
}

在您的Activity或Fragment中使用getRealPathFromURI函数来获取真实路径,绕过URI:

val fileRealPath = getRealPathFromURI(context!!, fileURI) ?: ""

你好, 在我的情况下,它进入了isDownloadDocument路径,但_id是msf:24,不是raw:&也不是数字。 你能帮忙吗? - Sanskar Dahiya
@SanskarDahiya 如果 id.startsWith("msf:") 就试试这种方式 https://dev59.com/0VIH5IYBdhLWcg3wkvtX#62154537 - Shailendra Madda
你好, 我已经检查过了,但是内存出现了问题。 因此,请根据Andorid文档创建一些解决方案: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); } - Sanskar Dahiya
请将其作为新问题发布。 - Shailendra Madda

15
您可以使用此代码选择视频路径。
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();

您可以参考下面的链接以获取帮助。

从mediastore获取URI的文件名和路径

最新的文件提供程序(API 29):

请按照以下链接进行操作:

博客:https://blogs.datanapps.com/media-picker Github:https://github.com/datanapps/MediaPicker

我希望您能成功。


试试这个,也许能对你有所帮助。否则我明天会更新答案。 https://www.journaldev.com/23219/android-capture-image-camera-gallery-using-fileprovider - Yogendra
@PriyankaSingh 请尝试此链接,希望对您有所帮助。 https://github.com/datanapps/MediaPicker - Yogendra

7

大多数答案对相册和相机图像都不起作用。这个方法适用于我的情况。

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; 
} 

7

这是我之前使用过的一些内容:

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;
}

1
游标为空。 - hkchakladar
3
这适用于媒体内容(来自媒体内容提供商),但不适用于存储访问框架文件。 - Robin Davies
@PriyankaSingh 您已经接受了一个答案。如果您已经进一步了解并且现在有稍微不同的问题,请发布一个新的、具体的问题。 - Ken Wolf
@KenWolf 接受的答案并不适用于所有版本。 - Priyanka Singh

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

            }
        }

5

以下是通过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();
        }
    }
}

2
这段代码无法在Android 10及更高版本上运行,因为DATA已不再可访问。在早期的Android版本上它也不太稳定。 - CommonsWare
这对其他文件类型如音频文件有效吗? 同时,正如@CommonsWare所说,“DATA”已被弃用。 - Mohammad Desouky
2
MediaStore.Images.Media.DATA已被弃用。 - Milan Sheth

4

在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;
    }

1
我尝试解决这个问题已经两三天了,但我发现的所有可能的解决方案都没有帮助。我一直得到空游标和类似的错误。
我需要文件路径的原因是获取Exif数据,以便能够正确显示图像方向。(请参见如何从URI获取Exif数据的最终答案
我找到了这个开源项目- 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) 
{
}

我知道这并不是直接回答问题,但由于我通过尝试解决这个问题找到了这个线程,我认为我的答案可能会帮助其他人。


1

像这样调用

 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;
}

1
java.lang.IllegalStateException: 无法从CursorWindow读取第0行、第-1列的数据。在访问数据之前请确保正确初始化Cursor。 - hkchakladar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接