获取 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,uriStringcontent://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

Android:如何获取匹配缩略图 URI 的文件路径?

Android Q - 如何获取下载文件夹的真实路径

java 从URI中获取图片真实路径

java 根据URI获取文件真实路径