从媒体存储中获取URI的文件名和路径。

443
我有一个从mediastore图像选择返回的onActivityResult,我可以使用以下方法获取图像的URI:
Uri selectedImage = data.getData();

将这个转换为字符串得到这个结果:
content://media/external/images/media/47

或者给出一个路径:
/external/images/media/47

然而,我似乎找不到一种将其转换为绝对路径的方法,因为我想将图像加载到位图中而无需将其复制到其他位置。我知道可以使用URI和内容解析器来实现这一点,但是在手机重新启动时,这种方法似乎会出现问题,我猜想MediaStore在重新启动后不会保持相同的编号。

1
https://gist.github.com/tatocaster/32aad15f6e0c50311626 - Shubham AgaRwal
API 19及以上的解决方案在这里,https://dev59.com/fnA75IYBdhLWcg3wPmd8#51227392。希望这可以帮助到大家。 - Sheikh Hasib
32个回答

642

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

3
Drive应用对我来说无法使用。URI为content://com.google.android.apps.docs.files/exposed_content/tHV4PoDlSl1OAu3qtER7rQ%3D%3D%0A%3BG1D2s6GYCEX7Niqtuj%2F7BWa71jRnlkCknibIU24b%2FO5BROqc0NMwnGsVaAIvxSTN%0A - Gabriel Augusto
18
正如 Christopher 指出的那样 - 这在 4.4+ 版本中不被支持。有关更多信息,请参阅此问题:https://dev59.com/YmIj5IYBdhLWcg3wnmXA#20402190?noredirect=1#comment30507493_20402190 - ılǝ
16
无法工作,光标为空。我不是在Android 4.4+上,而是在4.1.2上。 - matteo
11
在5个设备上进行测试,除了Android 4.1.2以外的所有设备都返回null。在所有更新的Android版本上也是如此。 - Fatima
3
数据常量在Android Q(10)中已被弃用。 - Nasib
显示剩余22条评论

133

关于第一个答案的简单更新: mActivity.managedQuery() 现在已经被弃用了。我已经使用新的方法更新了代码。

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

Android开发者文档


4
这对我没用。当我在文件浏览器中单击文件时,它可以工作,但是当我单击电子邮件附件时,仍然会出现“content://…”的东西。我尝试了这里所有的建议但没有成功。你知道为什么吗? - Luis A. Florit
@Luis 我也遇到了同样的问题。 - Linkandzelda
1
@dextor 你需要关闭游标。 - etherton
你能帮忙解决这个问题吗:https://dev59.com/nYXca4cB1Zd3GeqPInU_#27103868 - Chlebta
它适用于其他文件而不仅仅是图像文件吗,比如文本文件、doc、pdf等等? - Shailendra Madda
显示剩余7条评论

120

奥利奥饼干

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).

对于所有低于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());
}

9
这是唯一可以无缝运行在每种Uri类型上的版本——应该是最佳答案。 - Matthew Fisher
6
只有当用户没有在SD卡中选择文件时,这段代码才能正常工作。如果用户从SD卡中选择了文件,则返回的路径会例如是/storage/emulated/0/filePath,即使文件实际上位于/storage/sdCard/filePath。 - adi9090
2
你可以尝试使用一些库,比如适用于Android的Material Picker。链接:https://github.com/nbsp-team/MaterialFilePicker 这可以让你更接近解决方案,我仍在研究中,如果你有任何解决方案,请在下面发布。 - Ali Nawaz
6
也无法工作:java.lang.UnsupportedOperationException: 不支持的URI内容://com.android.externalstorage.documents/tree/primary%3ADCIM%2FCamera......为什么Android团队要让生活变得如此困难。 - Leon
1
这在Android 9.0(Pie)中无法用于下载的PDF文件。 - Akshay Bhat 'AB'
显示剩余18条评论

112

不要试图在文件系统中查找URI,这样查找数据库中的内容会很慢。

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

InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();

5
实际上,这是唯一正确的回答。没人真正在乎文件名,我们需要的是内容。实际文件可能在应用程序的私有文件夹中、互联网上、sqlite数据库中或完全是虚拟的并即时生成的。 - durilka
24
具体问题是关于文件名和路径的。是的,OP希望从文件中提取位图,但并非所有人都需要路径来寻找它。有时我们需要实际的文件内容。 - Huperniketes
3
举个例子:如果这个文件是一个视频,而你需要缩略图,那么函数“ThumbnailUtils.createVideoThumbnail”只能通过String类型的路径来调用,无法接受任何类型的输入流。 - ElYeante
1
我首先会检查视频内容提供商是否提供了元数据和缩略图。Android 的理念是“如果别人已经实现了,就不要自己再造轮子”。每个雄心勃勃的应用程序都试图创建自己的照片捕获功能,这真的让我感到很困惑。 - durilka
4
您刚刚介绍了一条导致 OutOfMemory 错误的路径。 - sandalone
显示剩余5条评论

43

以下是我获取文件名的示例代码,适用于像file://...和content://...这样的URI。它不仅适用于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;
}

4
这个能够在file://和content:// URI之间相互转换吗?我尝试将这段代码加入我的项目中,但它显示无法解析ApplicationObject。 - user280109
5
这段话的意思是:这是关于ApplicationObject的问题,能否给我一些相关代码?I'll translate and polish it: 这是关于ApplicationObject的问题,您能否提供一些相关的代码? - Nikolay Nikiforchuk
2
这个回答值得成为最佳答案,它更加全面并且解决了我所面对的问题。 - Andreas Rudolph
为什么在getLastPathSegment()已经返回一个字符串的情况下,还要调用getLastPathSegment().toString()呢? - droid8421
2
列“_data”不存在。 - hkchakladar
显示剩余5条评论

18

这里有很好的现成答案,其中一些我用来创造我的答案:

我需要从URI中获取路径并从路径中获取URI,但Google很难区分它们,所以对于任何遇到同样问题的人(例如,从已知物理位置获取视频MediaStore的缩略图),我们需要处理前者:

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

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

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

我通常这样做(用于视频,但也可以用于音频、文件或其他类型的存储内容,只需将MediaStore.Video(等等)替换为MediaStore.Audio):

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

基本上,MediaStoreDATA 列(或者你查询的子部分)存储了文件路径,因此你可以使用已知信息查找 DATA 字段,或者使用该字段查找其他想要的内容。

然后,我进一步使用以上提到的 Scheme 来确定如何处理我的数据:

 private boolean  getSelectedVideo(Intent imageReturnedIntent, boolean fromData) {

    Uri selectedVideoUri;

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

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

    String filePath;

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

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

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

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

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

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

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

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

     return true;
 }

通过使用您的从URI获取路径的代码,我可以返回用于稍后在React Native中保存到CameraRoll中的路径,谢谢。 - V-SHY

14

现在的事情变得更加复杂了,特别是在API级别29 Android Q之后。

  • 您必须在manifest.xml中请求requestLegacyStorage

  • 以下是从内容Uri获取文件名的方法

      public static String getNameFromContentUri(Context context, Uri contentUri){  
                          Cursor returnCursor = context.getContentResolver().query(contentUri, null, null, null, null);
                          int nameColumnIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                          returnCursor.moveToFirst();
                          String fileName = returnCursor.getString(nameColumnIndex);
                          return fileName;}
  • 这是获取所有Android版本Content Uri的完整路径的方法

  • JAVA

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

    Kotlin

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


    1
    使用"_data"与使用"MediaStore.Images.Media.DATA"相同,但后者从API 29开始已被弃用。 - vigilancer
    这是不推荐使用的,因为应用程序可能没有权限使用它,对于已被授予权限的应用程序可以使用它。 - Nasib
    3
    我的意思是 getDataColumn 正在使用已弃用的 _data 列,并且您正在针对每个 API 级别调用 getDataColumn - vigilancer

    12

    这些答案都不能完全解决我的问题。我不得不直接查看Google文档,并找到了这个有用的方法:

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

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


    1
    但是,如果我们想要一个路径而不是位图,那该怎么办? - Deven

    10

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

    6
    首先,你初始化了光标两次!其次,这段代码在这一行抛出“CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0”异常:path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); - Harshil Pansare
    我正在使用Oreo原生安卓系统,但由于某些原因它无法正常工作。 - Harshil Pansare
    如何从URI获取PDF文件路径?你能帮我吗? - user9427911
    @HarshilPansare,你是怎么让它在Android Oreo上运行的?我已经卡了两天了。 - BATMAN
    如果所选项不是图像,则此方法无效。 - Mustansir
    1
    @Mustansir:图片也不起作用。第二条查询没有返回任何内容。 - KMC

    9

    在过去的Android Q版本中,当MediaStore.Images.Media.DATA不再可用时,有什么方法吗?该字段在Android Q中已被弃用:

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

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

    我所知道的是,在过去的Android Q中,唯一的方法是依靠 RELATIVE_PATH

    该媒体项目在存储设备内的相对路径。例如,存储在 /storage/0000-0000/DCIM/Vacation/IMG1024.JPG 的项目将具有 DCIM/Vacation/ 路径。

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


    在Android Q中,所有文件都有相对路径吗?还是我们需要添加它们?比如,如果文件已经存在于设备上,那么它的相对路径会可用吗? - 1234567
    1
    根据链接中的描述,如果将@1234567传递为null,则系统会正确设置它。如果文件已经存在,则媒体扫描器应该添加该字段。 - Malachiasz
    1
    你需要将Android Q作为目标API,可能需要打开Scoped存储。 - Malachiasz
    按相对路径和显示名称搜索:https://dev59.com/-3ENtIcB2Jgan1zn_KYi#75568609 - Lifeweaver
    通过相对路径和显示名称进行搜索:https://stackoverflow.com/a/75568609/2137125 - undefined

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