You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scoped Storage:无需SAF,能否通过绝对路径获取图片Uri?

解决API 29+通过绝对路径获取图片宽高的问题

我明白你的痛点——不想为了适配Scoped Storage去修改用户和服务器数据库,但直接把绝对路径转Uri调用decodeStream会触发FileNotFoundException,这是因为你用Uri.parse(path)生成的Uri没有对应的Content Provider支持,系统无法通过ContentResolver访问到文件。下面给你几种规避方案,不用大规模修改数据库就能实现获取图片宽高的需求:


方案1:兼容模式下直接用BitmapFactory.decodeFile(API 29可用)

如果你的应用targetSdkVersion < 29,或者在AndroidManifest里添加了android:requestLegacyExternalStorage="true"(API 29下有效,API 30+会被逐渐限制),可以直接用绝对路径调用decodeFile来解码图片边界,完全不用碰Uri:

// 只解码图片边界,不加载完整位图,节省内存
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

// 传入绝对路径直接解码
BitmapFactory.decodeFile("/storage/emulated/0/DCIM/Camera/20200128_122949_020.jpg", options);

// 获取宽高
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;

这个方法最省心,不需要修改任何存储的路径字段,直接沿用原来的绝对路径即可。


方案2:API 30+直接用FileInputStream读取(私有目录/自有文件)

如果你的应用已经升级到targetSdkVersion >= 30,requestLegacyExternalStorage不再生效,那针对自己应用生成的图片(比如存放在应用私有目录getExternalFilesDir()下的文件),可以直接用FileInputStream来解码边界:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

File imageFile = new File("/storage/emulated/0/Android/data/your.package.name/files/photos/xxx.jpg");
try (FileInputStream fis = new FileInputStream(imageFile)) {
    BitmapFactory.decodeStream(fis, new Rect(), options);
} catch (IOException e) {
    // 处理文件读取异常
    e.printStackTrace();
}

int imageWidth = options.outWidth;
int imageHeight = options.outHeight;

这种方式绕开了ContentResolver,直接通过文件流读取,不需要Uri,也不用修改数据库。


方案3:公共目录图片通过绝对路径查询MediaStore获取Uri

如果图片是系统相机、图库等公共目录下的文件,API 30+无法直接通过绝对路径访问,这时候可以通过绝对路径去MediaStore查询对应的Content Uri,不用修改数据库存储的路径,只是在解码前做一次转换:

// 根据绝对路径获取对应的Content Uri
private Uri getImageUriFromPath(Context context, String absolutePath) {
    Uri contentUri = null;
    String[] projection = {MediaStore.Images.Media._ID};
    // 用绝对路径作为查询条件
    String selection = MediaStore.Images.Media.DATA + " = ?";
    String[] selectionArgs = {absolutePath};

    Cursor cursor = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection,
            selection,
            selectionArgs,
            null);

    if (cursor != null && cursor.moveToFirst()) {
        long imageId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
        contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId);
        cursor.close();
    }
    return contentUri;
}

// 调用示例
Uri imageUri = getImageUriFromPath(context, "/storage/emulated/0/DCIM/Camera/20200128_122949_020.jpg");
if (imageUri != null) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    try (InputStream is = context.getContentResolver().openInputStream(imageUri)) {
        BitmapFactory.decodeStream(is, new Rect(), options);
        int width = options.outWidth;
        int height = options.outHeight;
        // 使用宽高
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:这个方法依赖MediaStore的索引,如果图片是刚创建还没被系统扫描到,可能查询不到Uri,这时候可以考虑手动触发Media扫描,或者如果是你自己的应用保存的公共目录图片,建议保存的时候直接记录MediaStore返回的Uri。


内容的提问来源于stack exchange,提问作者whereismaxmax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 00:07:29