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

Android中如何从Content Uri获取File格式的文件路径?

从Content Uri获取本地file://路径的解决办法

你当前代码里直接拿uri.getPath()创建File是错误的——content://开头的Uri是Android内容提供者的统一标识,它的getPath()部分并非真实的本地文件路径,自然无法转换成file://格式。下面给你两种可行的解决思路:

方法一:解析Content Uri到真实外部存储路径(限可公开访问的文件)

如果文件在外部存储且能被系统媒体库索引,可以通过ContentResolver结合DocumentsContract解析出真实路径:

先添加工具方法:

public String getRealPathFromContentUri(Context context, Uri uri) {
    String filePath = null;
    // 处理DocumentProvider类型的Uri
    if (DocumentsContract.isDocumentUri(context, uri)) {
        // 外部存储文档
        if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            if ("primary".equalsIgnoreCase(split[0])) {
                filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
            }
        }
        // 下载目录文档
        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.parseLong(id));
            filePath = getDataColumn(context, contentUri, null, null);
        }
        // 媒体文件(图片/视频/音频)
        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;
            switch (type) {
                case "image":
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    break;
                case "video":
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    break;
                case "audio":
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    break;
            }

            filePath = getDataColumn(context, contentUri, "_id=?", new String[]{split[1]});
        }
    }
    // 普通content:// Uri
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        filePath = getDataColumn(context, uri, null, null);
    }
    // 已经是file:// Uri的情况
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        filePath = uri.getPath();
    }
    return filePath;
}

// 从ContentResolver查询_data列获取路径
private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String[] projection = {"_data"};

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            int columnIndex = cursor.getColumnIndexOrThrow("_data");
            return cursor.getString(columnIndex);
        }
    } finally {
        if (cursor != null) cursor.close();
    }
    return null;
}

然后修改你的viewPdf方法:

private void viewPdf(Intent getPdf, String action) {
    Uri uri = getPdf.getData(); // 直接用getData(),无需重复parse
    if (uri != null) {
        String realPath = getRealPathFromContentUri(this, uri);
        if (realPath != null) {
            String fileSchemePath = "file://" + realPath;
            name = new File(realPath).getName();
            path = fileSchemePath;
            Log.d("sdsfgsdfsdf", "拿到的file路径:" + fileSchemePath);
        } else {
            // 解析失败,切换到缓存方案
            String cachedPath = copyToCache(this, uri);
            if (cachedPath != null) {
                path = "file://" + cachedPath;
                Log.d("sdsfgsdfsdf", "缓存后的file路径:" + path);
            }
        }
    }
}

方法二:复制文件到应用缓存(通用所有情况)

如果文件是其他应用的私有文件,或者解析真实路径失败,可将Content Uri对应的文件复制到自己应用的缓存目录,再使用缓存文件的路径:

private String copyToCache(Context context, Uri uri) {
    try {
        InputStream input = context.getContentResolver().openInputStream(uri);
        if (input == null) return null;

        File cacheDir = context.getCacheDir();
        File tempPdf = new File(cacheDir, "temp_pdf_" + System.currentTimeMillis() + ".pdf");

        OutputStream output = new FileOutputStream(tempPdf);
        byte[] buffer = new byte[1024];
        int len;
        while ((len = input.read(buffer)) != -1) {
            output.write(buffer, 0, len);
        }

        input.close();
        output.close();
        return tempPdf.getAbsolutePath();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

重要提醒

  • Android 10及以上版本,直接访问外部存储需要MANAGE_EXTERNAL_STORAGE权限,否则方法一可能失效,建议优先使用ContentResolver操作文件,而非强行转换真实路径。
  • 缓存文件使用完毕后记得删除,避免占用应用缓存空间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 11:45:23