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

ste*_*ter 376 android uri absolute-path mediastore

onActivityResult从mediastore图像选择返回,我可以使用以下内容获取图像的URI:

Uri selectedImage = data.getData();
Run Code Online (Sandbox Code Playgroud)

将其转换为字符串可以得到:

content://media/external/images/media/47
Run Code Online (Sandbox Code Playgroud)

或者路径给出:

/external/images/media/47
Run Code Online (Sandbox Code Playgroud)

但是我似乎无法找到将其转换为绝对路径的方法,因为我想将图像加载到位图而不必将其复制到某处.我知道这可以使用URI和内容解析器完成,但这似乎在重新启动手机时中断,我想MediaStore在重新启动之间不会保持其编号相同.

Miš*_*eić 603

在API 19下面使用此代码从URI获取文件路径:

public String getRealPathFromURI(Context context, Uri contentUri) {
  Cursor cursor = null;
  try { 
    String[] proj = { MediaStore.Images.Media.DATA };
    cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
  } finally {
    if (cursor != null) {
      cursor.close();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用具有相同参数的getContentResolver().query(.....)代替managedQuery(.........)(已弃用).干得好 (65认同)
  • 在最新的Android版本(KitKat)中,这会产生错误:路径String为null. (42认同)
  • 正如克里斯托弗指出的那样 - 4.4+不支持这个问题.欲了解更多信息,请参阅此问题:http://stackoverflow.com/questions/20067508/get-real-path-from-uri-android-kitkat-new-storage-access -framework/20402190?noredirect = 1个#comment30507493_20402190 (17认同)
  • 不行.cursor为null.我不在Android 4.4+上,我在4.1.2上. (13认同)
  • 在5台设备上测试过.除Android 4.1.2外,其他所有内容均为null.在所有较新的Androids上返回null. (11认同)
  • 使用云端硬盘应用不适合我.URI:content://com.google.android.apps.docs.files/exposed_content/tHV4PoDlSl1OAu3qtER7rQ%3D%3D%0A%3BG1D2s6GYCEX7Niqtuj%2F7BWa71jRnlkCknibIU24b%2FO5BROqc0NMwnGsVaAIvxSTN%0A (2认同)
  • Android Q(10) 中已弃用 data 常量 (2认同)

Seb*_*ano 125

只是第一个答案的简单更新:mActivity.managedQuery()现已弃用.我用新方法更新了代码.

private String getRealPathFromURI(Uri contentUri) {
    String[] proj = { MediaStore.Images.Media.DATA };
    CursorLoader loader = new CursorLoader(mContext, contentUri, proj, null, null, null);
    Cursor cursor = loader.loadInBackground();
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String result = cursor.getString(column_index);
    cursor.close();
    return result;
}
Run Code Online (Sandbox Code Playgroud)

android dev源码

  • @dextor:这对我不起作用.当我在文件浏览器中单击文件时,它可以正常工作,但是当我点击电子邮件附件时,我仍然会得到`content:// ...'的东西.我没有运气就尝试了所有的建议.知道为什么吗? (3认同)

Jit*_*iya 106

对于奥利奥

Uri uri = data.getData(); 
File file = new File(uri.getPath());//create path from uri
final String[] split = file.getPath().split(":");//split the path.
filePath = split[1];//assign it to a string(your choice).
Run Code Online (Sandbox Code Playgroud)

对于Oreo下面的所有版本,我已经制作了这个从uri获得真实路径的方法

 @SuppressLint("NewApi")
    public static String getFilePath(Context context, Uri uri) throws URISyntaxException {
        String selection = null;
        String[] selectionArgs = null;
        // Uri is different in versions after KITKAT (Android 4.4), we need to
        if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            } else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                uri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            } else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("image".equals(type)) {
                    uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }
                selection = "_id=?";
                selectionArgs = new String[]{
                        split[1]
                };
            }
        }
        if ("content".equalsIgnoreCase(uri.getScheme())) {


          if (isGooglePhotosUri(uri)) {
              return uri.getLastPathSegment();
           }

            String[] projection = {
                    MediaStore.Images.Media.DATA
            };
            Cursor cursor = null;
            try {
                cursor = context.getContentResolver()
                        .query(uri, projection, selection, selectionArgs, null);
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                if (cursor.moveToFirst()) {
                    return cursor.getString(column_index);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        return null;
    }

    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

  public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一一个在每种类型的Uri上无缝工作的版本 - 应该是最好的答案.. (7认同)
  • 如果用户未从SD卡中选择文件,则此代码有效.如果用户从SD卡中选择了文件而不是返回的路径,例如/ storage/emulated/0/filePath,即使文件位于/ storage/sdCard/filePath (6认同)
  • 也不起作用:java.lang.UnsupportedOperationException:不支持的Uri内容://com.android.externalstorage.documents/tree/primary%3ADCIM%2FCamera ....为什么android团队让生活变得如此艰难 (3认同)
  • 那么你可以尝试一些像android url的材料选择器的库:https://github.com/nbsp-team/MaterialFilePicker这可以让你更接近解决方案我仍然在它上面如果你得到任何解决方案,请在下面发布它... (2认同)

mig*_*mig 95

不要试图在文件系统中找到一个uri,这在数据库中查找起来很慢.

您可以通过向工厂提供输入流来获取uri的位图,就像您将文件提供给工厂一样:

InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
Run Code Online (Sandbox Code Playgroud)

  • 提出的具体问题是文件名和路径.是的,OP正在寻找从文件中获取位图,但是每个寻找路径的人都不是这样.有时我们需要实际的文件内容. (16认同)
  • 实际上这是唯一正确的回应.没有人真正关心文件名.我们需要的是内容.实际文件可能位于应用程序的私人文件夹中,可以是Internet,sqlite,也可以是纯虚拟的,并且可以即时生成. (5认同)
  • 您刚刚介绍了导致OutOfMemory错误的路径 (4认同)
  • @durilka,一个例子:如果文件是一个视频而你想要一个缩略图,可以使用String类型的路径调用函数"ThumbnailUtils.createVideoThumbnail",不接受任何inputStreams的tipe. (3认同)

Nik*_*huk 38

这是我从URI获取文件名的例子,例如file:// ...和content:// .... 它不仅适用于Android MediaStore,也适用于EzExplorer等第三方应用程序.

public static String getFileNameByUri(Context context, Uri uri)
{
    String fileName="unknown";//default fileName
    Uri filePathUri = uri;
    if (uri.getScheme().toString().compareTo("content")==0)
    {      
        Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
        if (cursor.moveToFirst())
        {
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
            filePathUri = Uri.parse(cursor.getString(column_index));
            fileName = filePathUri.getLastPathSegment().toString();
        }
    }
    else if (uri.getScheme().compareTo("file")==0)
    {
        fileName = filePathUri.getLastPathSegment().toString();
    }
    else
    {
        fileName = fileName+"_"+filePathUri.getLastPathSegment();
    }
    return fileName;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是ApplicationObject的问题,你能给我一些代码吗? (5认同)
  • 这可以在file://和content:// URI之间转换,反之亦然?我尝试在我的项目中包含代码,但它说ApplicationObject无法解析. (4认同)
  • 这应该是最好的答案,它更全面,解决了我遇到的问题. (2认同)
  • 列“_data”不存在 (2认同)

Jon*_*n O 15

很好的现有答案,其中一些我曾经拿出自己的答案:

我必须从URI获取路径并从路径获取URI,并且谷歌很难分辨出具有相同问题的任何人(例如,从MediaStore已经拥有物理位置的视频中获取缩略图)).前者:

/**
 * Gets the corresponding path to a file from the given content:// URI
 * @param selectedVideoUri The content:// URI to find the file path from
 * @param contentResolver The content resolver to use to perform the query.
 * @return the file path as a string
 */
private String getFilePathFromContentUri(Uri selectedVideoUri,
        ContentResolver contentResolver) {
    String filePath;
    String[] filePathColumn = {MediaColumns.DATA};

    Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}
Run Code Online (Sandbox Code Playgroud)

后者(我为视频做,但也可以通过将MediaStore.Audio(等)替换为MediaStore.Video来用于音频或文件或其他类型的存储内容):

/**
 * Gets the MediaStore video ID of a given file on external storage
 * @param filePath The path (on external storage) of the file to resolve the ID of
 * @param contentResolver The content resolver to use to perform the query.
 * @return the video ID as a long
 */
private long getVideoIdFromFilePath(String filePath,
        ContentResolver contentResolver) {


    long videoId;
    Log.d(TAG,"Loading file " + filePath);

            // This returns us content://media/external/videos/media (or something like that)
            // I pass in "external" because that's the MediaStore's name for the external
            // storage on my device (the other possibility is "internal")
    Uri videosUri = MediaStore.Video.Media.getContentUri("external");

    Log.d(TAG,"videosUri = " + videosUri.toString());

    String[] projection = {MediaStore.Video.VideoColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(projection[0]);
    videoId = cursor.getLong(columnIndex);

    Log.d(TAG,"Video ID is " + videoId);
    cursor.close();
    return videoId;
}
Run Code Online (Sandbox Code Playgroud)

基本上,DATAMediaStore(或任何它要查询的子部分)存储的文件路径,让你无论是使用你知道要查找什么DATA字段,或者使用字段来查找你想要的任何东西.

然后我进一步使用Scheme上面的内容来弄清楚如何处理我的数据:

 private boolean  getSelectedVideo(Intent imageReturnedIntent, boolean fromData) {

    Uri selectedVideoUri;

    //Selected image returned from another activity
            // A parameter I pass myself to know whether or not I'm being "shared via" or
            // whether I'm working internally to my app (fromData = working internally)
    if(fromData){
        selectedVideoUri = imageReturnedIntent.getData();
    } else {
        //Selected image returned from SEND intent 
                    // which I register to receive in my manifest
                    // (so people can "share via" my app)
        selectedVideoUri = (Uri)getIntent().getExtras().get(Intent.EXTRA_STREAM);
    }

    Log.d(TAG,"SelectedVideoUri = " + selectedVideoUri);

    String filePath;

    String scheme = selectedVideoUri.getScheme(); 
    ContentResolver contentResolver = getContentResolver();
    long videoId;

    // If we are sent file://something or content://org.openintents.filemanager/mimetype/something...
    if(scheme.equals("file") || (scheme.equals("content") && selectedVideoUri.getEncodedAuthority().equals("org.openintents.filemanager"))){

        // Get the path
        filePath = selectedVideoUri.getPath();

        // Trim the path if necessary
        // openintents filemanager returns content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.mp4
        if(filePath.startsWith("/mimetype/")){
            String trimmedFilePath = filePath.substring("/mimetype/".length());
            filePath = trimmedFilePath.substring(trimmedFilePath.indexOf("/"));
        }

        // Get the video ID from the path
        videoId = getVideoIdFromFilePath(filePath, contentResolver);

    } else if(scheme.equals("content")){

        // If we are given another content:// URI, look it up in the media provider
        videoId = Long.valueOf(selectedVideoUri.getLastPathSegment());
        filePath = getFilePathFromContentUri(selectedVideoUri, contentResolver);

    } else {
        Log.d(TAG,"Failed to load URI " + selectedVideoUri.toString());
        return false;
    }

     return true;
 }
Run Code Online (Sandbox Code Playgroud)


YYa*_*mil 10

在所有情况下,这些答案都不适用于我.我不得不直接访问Google的文档https://developer.android.com/guide/topics/providers/document-provider.html,并找到了这个有用的方法:

private Bitmap getBitmapFromUri(Uri uri) throws IOException {
    ParcelFileDescriptor parcelFileDescriptor =
    getContentResolver().openFileDescriptor(uri, "r");
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
    parcelFileDescriptor.close();
    return image;
}
Run Code Online (Sandbox Code Playgroud)

您可以使用此位图在图像视图中显示它.


Has*_*ter 8

API 19 及更高版本来自 Uri 的图像文件路径完美运行。我还检查了这个最新的PIE API 28

public String getImageFilePath(Uri uri) {
    String path = null, image_id = null;

    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    if (cursor != null) {
        cursor.moveToFirst();
        image_id = cursor.getString(0);
        image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
        cursor.close();
    }

    Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
    if (cursor!=null) {
        cursor.moveToFirst();
        path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
    }
    return path;
}
Run Code Online (Sandbox Code Playgroud)

  • 首先,你已经初始化了两次游标!其次,这段代码抛出 `CursorIndexOutOfBoundsException: Index 0 requests, with a size of 0` 在这一行: `path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));` (5认同)

Nas*_*sib 7

现在事情变得复杂了,尤其是在 API 级别 29 Android Q 之后。 这就是你应该如何从内容 Uri 中获取文件名

        public static String getNameFromContentUri(Context context, Uri contentUri){  
                            Cursor returnCursor = context.getContentResolver().query(contentUri, null, null, null, null);
                            int nameColumnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                            returnCursor.moveToFirst();
                            String fileName = returnCursor.getString(nameColumnIndex);
                            return fileName;}
Run Code Online (Sandbox Code Playgroud)

这就是您获取所有 android 版本的 Content Uri 完整路径的方法

爪哇

    public static String getFullPathFromContentUri(final Context context, final Uri uri) {
    
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    if ("primary".equalsIgnoreCase(type)) {
                        return Environment.getExternalStorageDirectory() + "/" + split[1];
                    }//non-primary e.g sd card
                     else {

                           if (Build.VERSION.SDK_INT > 20) {
                    //getExternalMediaDirs() added in API 21
                    File extenal[] = context.getExternalMediaDirs();
                   for (File f : extenal) {
                    filePath = f.getAbsolutePath();
                    if (filePath.contains(type)) {
                        int endIndex = filePath.indexOf("Android");
                        filePath = filePath.substring(0, endIndex) + split[1];
                    }
                }
             }else{
                    filePath = "/storage/" + type + "/" + split[1];
             }
            return filePath;
        }
                }
                // DownloadsProvider
                else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
    
                    final String id = DocumentsContract.getDocumentId(uri);
                    final Uri contentUri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                    return getDataColumn(context, contentUri, null, null);
                }
                // MediaProvider
                else if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
    
                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{
                            split[1]
                    };
    
                       Cursor cursor = null;
                       final String column = "_data";
                       final String[] projection = {
                          column
                        };
       
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                        null);
                if (cursor != null && cursor.moveToFirst()) {
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
                }
            }
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
                return getDataColumn(context, uri, null, null);
            }
            // File
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
    
            return null;
        }

    private static String getDataColumn(Context context, Uri uri, String selection,
                                     String[] selectionArgs) {
    
            Cursor cursor = null;
            final String column = "_data";
            final String[] projection = {
                    column
            };
    
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                        null);
                if (cursor != null && cursor.moveToFirst()) {
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
Run Code Online (Sandbox Code Playgroud)

科特林

companion object {
@JvmStatic
    @SuppressLint("NewApi")
    fun getPath(context: Context, uri: Uri): String? {
        val isKitKat: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":").toTypedArray()
                val type = split[0]
                return if ("primary".equals(type, ignoreCase = true)) {
                    Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                } else { // non-primary volumes e.g sd card
                    var filePath = "non"
                    //getExternalMediaDirs() added in API 21
                    val extenal = context.externalMediaDirs
                    for (f in extenal) {
                        filePath = f.absolutePath
                        if (filePath.contains(type)) {
                            val endIndex = filePath.indexOf("Android")
                            filePath = filePath.substring(0, endIndex) + split[1]
                        }
                    }
                    filePath
                }
            } else if (isDownloadsDocument(uri)) {
                val id = DocumentsContract.getDocumentId(uri)
                val contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
                return getDataColumn(context, contentUri, null, null)
            } else if (isMediaDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":").toTypedArray()
                val type = split[0]
                var contentUri: Uri? = null
                if ("image" == type) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                } else if ("video" == type) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                } else if ("audio" == type) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                }
                val selection = "_id=?"
                val selectionArgs = arrayOf(
                        split[1]
                )
                return getDataColumn(context, contentUri, selection, selectionArgs)
            }
        } else if ("content".equals(uri.scheme, ignoreCase = true)) {
            return getDataColumn(context, uri, null, null)
        } else if ("file".equals(uri.scheme, ignoreCase = true)) {
            return uri.path
        }
        return null
    }

    private fun getDataColumn(context: Context, uri: Uri?, selection: String?,
                              selectionArgs: Array<String>?): String? {
        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(
                column
        )
        try {
            cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs,
                    null)
            if (cursor != null && cursor.moveToFirst()) {
                val column_index = cursor.getColumnIndexOrThrow(column)
                return cursor.getString(column_index)
            }
        } catch (e: java.lang.Exception) {
        } finally {
            cursor?.close()
        }
        return null
    }

    private fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    private fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    private fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }

}
Run Code Online (Sandbox Code Playgroud)

}

  • 我的意思是“getDataColumn”正在使用已弃用的“_data”列,并且您正在为每个 api 级别调用“getDataColumn”。 (3认同)

Sun*_*nil 6

尝试这个

不过,如果您遇到问题以获得真正的路径,您可以尝试我的答案。上面的答案对我没有帮助。

说明:- 此方法获取 URI,然后检查 Android 设备的 API 级别,然后根据 API 级别生成真实路径。根据API级别不同,生成真实路径方法的代码也不同。

  1. 从 URI 获取真实路径的方法

    @SuppressLint("ObsoleteSdkInt")
    public String getPathFromURI(Uri uri){
        String realPath="";
    // SDK < API11
        if (Build.VERSION.SDK_INT < 11) {
            String[] proj = { MediaStore.Images.Media.DATA };
            @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
            int column_index = 0;
            String result="";
            if (cursor != null) {
                column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                realPath=cursor.getString(column_index);
            }
        }
        // SDK >= 11 && SDK < 19
        else if (Build.VERSION.SDK_INT < 19){
            String[] proj = { MediaStore.Images.Media.DATA };
            CursorLoader cursorLoader = new CursorLoader(this, uri, proj, null, null, null);
            Cursor cursor = cursorLoader.loadInBackground();
            if(cursor != null){
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                realPath = cursor.getString(column_index);
            }
        }
        // SDK > 19 (Android 4.4)
        else{
            String wholeID = DocumentsContract.getDocumentId(uri);
            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];
            String[] column = { MediaStore.Images.Media.DATA };
            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";
            Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null);
            int columnIndex = 0;
            if (cursor != null) {
                columnIndex = cursor.getColumnIndex(column[0]);
                if (cursor.moveToFirst()) {
                    realPath = cursor.getString(columnIndex);
                }
                cursor.close();
            }
        }
        return realPath;
     }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 像这样使用这个方法

    Log.e(TAG, "getRealPathFromURI: "+getPathFromURI(your_selected_uri) );
    
    Run Code Online (Sandbox Code Playgroud)

输出:-

04-06 12:39:46.993 6138-6138/com.app.qtm E/标签:getRealPathFromURI:/storage/emulated/0/Video/avengers_infinity_war_4k_8k-7680x4320.jpg


Mal*_*asz 6

过去的Android Q 的任何方式,当 MediaStore.Images.Media.DATA 不再可用时?此字段在 Android Q 中已折旧:

此常量在 API 级别 29 中已弃用。应用程序可能没有直接访问此路径的文件系统权限。应用程序不应尝试直接打开此路径,而应使用 ContentResolver#openFileDescriptor(Uri, String) 来获取访问权限。

https://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#DATA

--- 编辑

据我所知,对于过去的 Android Q,唯一的方法是在RELATIVE_PATH上进行中继

此媒体项目在其被持久化的存储设备中的相对路径。例如,存储在 /storage/0000-0000/DCIM/Vacation/IMG1024.JPG 的项目的路径为 DCIM/Vacation/。

https://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html#RELATIVE_PATH


Shi*_*mar 5

试试这个从Uri获取图像文件路径

public void getImageFilePath(Context context, Uri uri) {

    Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
    cursor.moveToFirst();
    String image_id = cursor.getString(0);
    image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
    cursor.close();
    cursor = context.getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
    cursor.moveToFirst();
    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    cursor.close();
    upLoadImageOrLogo(path);
}
Run Code Online (Sandbox Code Playgroud)