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

Android开发:选择文件后如何获取含扩展名的真实完整文件路径

解决方案

问题根因

Android 4.4及以上版本中,ACTION_GET_CONTENT返回的默认是content://类型的URI,而非file://类型,直接调用Uri.getPath()获取到的是媒体库的索引标识,不是文件的真实物理路径。

实现步骤

1. 声明必要权限

在AndroidManifest.xml中添加存储读取权限,适配不同系统版本:

<!-- Android 12及以下版本所需权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Android 13及以上版本,仅需访问图片时申请该权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

2. 添加URI转真实路径工具方法

针对不同系统版本提供两种兼容方案:

方案一:直接查询媒体库获取物理路径(适用于Android 9及以下,或已适配分区存储的场景)

public String getRealPathFromURI(Context context, Uri contentUri) {
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
    if (cursor == null) return null;
    int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String path = cursor.getString(columnIndex);
    cursor.close();
    return path;
}

方案二:分区存储兼容方案(全版本适用,兼容性更高)

Android 10及以上开启分区存储后,直接查询媒体库路径可能返回空,可将选中文件拷贝到应用专属缓存目录后获取路径使用:

// 从URI获取文件名
private String getFileNameFromUri(Context context, Uri uri) {
    String fileName = null;
    Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
        cursor.close();
    }
    return fileName != null ? fileName : "temp_file";
}

// 将URI对应文件拷贝到应用缓存目录,返回缓存文件的完整路径
public String getCacheFilePathFromUri(Context context, Uri uri) throws IOException {
    File cacheFile = new File(context.getCacheDir(), getFileNameFromUri(context, uri));
    try (InputStream inputStream = context.getContentResolver().openInputStream(uri);
         FileOutputStream outputStream = new FileOutputStream(cacheFile)) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, length);
        }
    }
    return cacheFile.getAbsolutePath();
}

3. 修改onActivityResult逻辑

替换原有直接取路径的代码,调用上述工具方法:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 10 && resultCode == RESULT_OK && data != null) {
        TextView filename = findViewById(R.id.filenameTextView);
        Uri uri = data.getData();
        // 根据需求选择使用其中一种方案
        // String realPath = getRealPathFromURI(this, uri);
        String realPath = null;
        try {
            realPath = getCacheFilePathFromUri(this, uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (realPath != null) {
            directory = realPath;
            filename.setText(directory);
        }
    }
}

补充说明

如果仅需要展示文件名,不需要获取完整物理路径,可直接调用getFileNameFromUri方法获取带后缀的文件名,无需申请存储权限,兼容性最优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 16:18:03