首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

在Android 10中从Uri获取绝对路径

在Android 10(API 级别 29)及更高版本中,获取文件的绝对路径变得更加复杂,因为访问外部存储的权限和方式发生了变化。特别是,Scoped Storage 的引入限制了应用对外部存储的直接访问。

以下是一些常见的方法来从 Uri 获取文件的绝对路径:

1. 使用 ContentResolverCursor

对于某些类型的 Uri,你可以使用 ContentResolverCursor 来查询文件的路径。

代码语言:javascript
复制
public String getRealPathFromURI(Context context, Uri uri) {
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
    if (cursor != null) {
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String path = cursor.getString(column_index);
        cursor.close();
        return path;
    }
    return null;
}

2. 使用 DocumentFileFileDescriptor

对于 DocumentUri,你可以使用 DocumentFileFileDescriptor 来访问文件内容。

代码语言:javascript
复制
public String getFilePathFromURI(Context context, Uri uri) {
    if (DocumentsContract.isDocumentUri(context, uri)) {
        if (isExternalStorageDocument(uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            String[] split = docId.split(":");
            String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }
        } else if (isDownloadsDocument(uri)) {
            String id = DocumentsContract.getDocumentId(uri);
            Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        } else if (isMediaDocument(uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            String[] split = docId.split(":");
            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;
            }

            String selection = "_id=?";
            String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    } else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

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

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

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

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

3. 使用 FileUtils(适用于某些特定情况)

在某些情况下,你可以使用 FileUtils 类来处理文件的复制和路径获取。

代码语言:javascript
复制
public String getPathFromUri(Context context, Uri uri) {
    String filePath = null;
    if (DocumentsContract.isDocumentUri(context, uri)) {
        if (isExternalStorageDocument(uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            String[] split = docId.split(":");
            String type = split[0];
            if ("primary".equalsIgnoreCase(type)) {
                filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
            }
        } else if (isDownloadsDocument(uri)) {
            String id = DocumentsContract.getDocumentId(uri);
            Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            filePath = getDataColumn(context, contentUri, null, null);
        } else if (isMediaDocument(uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            String[] split = docId.split(":");
            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;
            }
            String selection = "_id=?";
            String[] selectionArgs = new String[] {
                    split[1]
            };
            filePath = getDataColumn(context, contentUri, selection, selectionArgs);
        }
    } else if ("content".equalsIgnoreCase(uri.getScheme())) {
        filePath = getDataColumn(context, uri, null, null);
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        filePath = uri.getPath();
    }
    return filePath;
}

注意事项

  1. 权限:确保你的应用具有访问外部存储的权限。在Android 10及更高版本中,你可能需要请求 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限。
  2. Scoped Storage:在Android 10及更高版本中,Scoped Storage 限制了对外部存储的访问。你可能需要使用 MediaStore API 或 SAF(Storage Access Framework)来访问文件。
  3. 兼容性:确保你的代码兼容不同的Android版本和设备。
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Android如何通过URI获取文件路径示例代码

前言 最近在工作的过程中,遇到不同 Android 版本下 URI 采用不同方式来获取文件路径的问题。...因为需求的原因,要求拍照上传或者相册中选择图片上传,而且图片是需要经过压缩的,大小不能超过2M。 很快,拍照的这部分就搞定了。那么相册中选择图片的也是一样的道理,应该也是轻松解决了。...onActivityResult(int requestCode, int resultCode, Intent data) 中获取URI 。...因为 Android 4.4 及以上的手机上,获取到的 URI 变成了 content://com.android.providers.media.documents/document/image%3A235700...这是因为 Android 4.4 及以上的机型,使用了 DocumentUri 来代表获取到文件的 URI 。 所以我们又要对于 DocumentUri 进行适配。

4K00
  • Android打开手机相册获取图片路径

    本文实例为大家分享了Android打开手机相册获取图片路径的具体代码,供大家参考,具体内容如下 根据打开相机返回的Uri uri = data.getData();获取该相片的真正SD卡路径!...,realPathFromUri 为真正路径 获取真正路径 package com.example.richeditortest; import android.annotation.SuppressLint...; public class RealPathFromUriUtils { /** * 根据Uri获取图片的绝对路径 * * @param context 上下文对象 * @param uri 图片的...(context, uri); } } /** * 适配api19以下(不包括api19),根据uri获取图片的绝对路径 * * @param context 上下文对象 * @param uri 图片的...获取图片的绝对路径 * * @param context 上下文对象 * @param uri 图片的Uri * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null

    4.5K30

    Android实现选择相册图片并显示功能

    ; public class RealPathFromUriUtils { /** * 根据Uri获取图片的绝对路径 * * @param context 上下文对象 * @param uri 图片的...Uri * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null */ public static String getRealPathFromUri(Context...(context, uri); } } /** * 适配api19以下(不包括api19),根据uri获取图片的绝对路径 * * @param context 上下文对象 * @param uri...获取图片的绝对路径 * * @param context 上下文对象 * @param uri 图片的Uri * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null...(uri.getScheme())) { // 如果是 file 类型的 Uri,直接获取图片对应的路径 filePath = uri.getPath(); } return filePath; } /

    96030

    Android 文件管理】分区存储 ( 创建与查询图片文件 )

    类型打开输出流 , 然后通过该输出流写出数据 , 文件创建完成 ; 图片创建流程 : 首先 , 获取 操作数据库的 Uri ; // 操作 external.db 数据库 // 获取 Uri 路径 var...Uri ; 这里获取外置 SD 卡 Pictures 目录对应的 Uri 对象 ; // 获取外置 SD 卡 Pictures 对应的 Uri 对象 var externalContentUri: Uri...(externalContentUri, id); Log.i(TAG, "查询到的 Uri = $uri , 路径 = $path , 文件名称 = $name , 绝对路径 = $absolutePath..., "查询到的 Uri = $uri , 路径 = $path , 文件名称 = $name , 绝对路径 = $absolutePath") // 关闭游标...42 数字 , 就是 " external.db " 数据库中 files 数据表中该 image.jpg 文件对应的 _id 字段数据 ; 绝对路径 Android 11 的 分区存储机制 中不能用来做任何操作

    1K20

    透过FileProvider再看ContentProvider

    Android7.0,Android提高了应用的隐私权,限制了应用间共享文件。如果需要在应用间共享,需要授予要访问的URI临时访问权限。...以下是官方说明: ★对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止您的应用外部公开 file:// URI。...可以看到,这个之前落伍的方案,自身到对方,都是不太好的选择。 所以Google就想了一个办法,把对文件的访问限制应用内部。...也正是因为这个属性为true,Android7.0以下,Android默认是将它当成一个普通的ContentProvider,外部无法通过content:// URI来访问文件。...很多人都知道该怎么配置FileProvider让别人(比如照相APP)来获取我们的Content URI,但是你们知道别人拿到Content URI之后又是怎么获取具体的File的呢?

    1.2K20

    Android 文件管理】分区存储 ( 修改与删除图片文件 )

    MediaStore 修改图片 ---- 将 /sdcard/Pictures/image/ 目录下的 image.jpg 修改为 image_update.jpg ; 分区存储机制中 , 删除图片文件 , 不能通过获取绝对路径进行删除..., // 指定查询参数 arrayOf("image.jpg"), // 排序规则 null ) 然后 , Cursor 中获取 MediaStore.Images.Media...删除 / 修改 操作了 ; 分区存储机制 中 , 只能通过文件的 Uri 地址操作文件的 增 删 查 改 ; 修改图片 : 构造 ContentValues , 将 display_name 修改成...MediaStore 删除图片 ---- 将 /sdcard/Pictures/image/ 目录下的 image_update.jpg 文件删除 ; 分区存储机制中 , 删除图片文件 , 不能通过获取绝对路径进行删除...删除 / 修改 操作了 ; 分区存储机制 中 , 只能通过文件的 Uri 地址操作文件的 增 删 查 改 ; 删除图片 : 调用 getContentResolver 方法获取 ContentResolver

    2.5K20

    Android 10适配要点,作用域存储

    Android 10开始,每个应用程序只能有权自己的外置存储空间关联目录下读取和创建文件,获取该关联目录的代码是:context.getExternalFilesDir()。...当然,这只是一种权宜之计,未来的Android系统版本中,这段配置随时都可能会失效(目前Android 11预览版已经确认,这段配置至少Android 11上不会失效)。...不同于过去可以直接获取到相册中图片的绝对路径作用域存储当中,我们只能借助MediaStore API获取到图片的Uri,示例代码如下: val cursor = contentResolver.query...而Android 10开始,我们已经不能以绝对路径的方式访问外置存储空间了,所以文件下载功能也会受到影响。 那么该如何解决呢?主要有以下两种方式。...然后onActivityResult()方法当中,我们就可以获取到用户选中文件的Uri,之后通过ContentResolver打开文件输入流来进行读取就可以了。 Demo效果: ?

    2.2K10

    FileProvider你了解多少?透过FileProvider来看看四大组件之一ContentProvider!

    Android7.0,Android提高了应用的隐私权,限制了应用间共享文件。如果需要在应用间共享,需要授予要访问的URI临时访问权限。...以下是官方说明: 对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止您的应用外部公开 file:// URI。...为什么限制应用间共享文件 打个比方,应用A有一个文件,绝对路径为file:///storage/emulated/0/Download/photo.jpg 现在应用A想通过其他应用来完成一些需求,比如拍照...可以看到,这个之前落伍的方案,自身到对方,都是不太好的选择。 所以Google就想了一个办法,把对文件的访问限制应用内部。...很多人都知道该怎么配置FileProvider让别人(比如照相APP)来获取我们的Content URI,但是你们知道别人拿到Content URI之后又是怎么获取具体的File的呢?

    79400
    领券