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

Java Android Studio中如何从content类型Uri获取文件绝对路径

Android Content Uri转本地绝对路径工具类

场景说明

需要转换的系统Uri典型示例如下:

  • content://com.android.providers.downloads.documents/document/msf%3A33346
  • content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2F2021-06-18Format%204.xls

这类Content Uri的格式会随手机机型、系统版本差异发生变化,目标是将其转换为类似storage/emulated/0/[文件路径]格式的标准本地文件路径。

可运行实现代码

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class FileUtils {
    /* 获取Uri对应的真实本地文件路径 */
    public static String getPath(Context ctx, Uri uri) {
        String ret;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                // Android 4.4及以上系统调用
                ret = getUriRealPathAboveKitkat(ctx, uri);
            } else {
                // Android 4.4以下系统调用
                ret = getRealPath(ctx.getContentResolver(), uri, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.d("DREG", "获取路径异常: " + e);
            // 直接读取Uri流复制为临时文件返回路径,兜底方案
            ret = getFilePathFromURI(ctx, uri);
        }
        return ret;
    }

    /* 兜底方案:读取Uri流复制到本地临时目录,返回新文件路径 */
    private static String getFilePathFromURI(Context context, Uri contentUri) {
        String fileName = getFileName(contentUri);
        if (!TextUtils.isEmpty(fileName)) {
            String TEMP_DIR_PATH = Environment.getExternalStorageDirectory().getPath();
            File copyFile = new File(TEMP_DIR_PATH + File.separator + fileName);
            Log.d("DREG", "复制生成临时文件: " + copyFile);
            copy(context, contentUri, copyFile);
            return copyFile.getAbsolutePath();
        }
        return null;
    }

    /* 从Uri中提取文件名 */
    public static String getFileName(Uri uri) {
        if (uri == null) return null;
        String fileName = null;
        String path = uri.getPath();
        int cut = path.lastIndexOf('/');
        if (cut != -1) {
            fileName = path.substring(cut + 1);
        }
        return fileName;
    }

    /* 将Uri对应的流复制到目标文件 */
    public static void copy(Context context, Uri srcUri, File dstFile) {
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
            if (inputStream == null) return;
            OutputStream outputStream = new FileOutputStream(dstFile);
            IOUtils.copy(inputStream, outputStream);
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /* Android 4.4及以上系统获取Uri真实路径逻辑 */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private static String getUriRealPathAboveKitkat(Context ctx, Uri uri) {
        String ret = "";
        if (ctx != null && uri != null) {
            if (isContentUri(uri)) {
                if (isGooglePhotoDoc(uri.getAuthority())) {
                    ret = uri.getLastPathSegment();
                } else {
                    ret = getRealPath(ctx.getContentResolver(), uri, null);
                }
            } else if (isFileUri(uri)) {
                ret = uri.getPath();
            } else if (isDocumentUri(ctx, uri)) {
                // 获取文档Id
                String documentId = DocumentsContract.getDocumentId(uri);
                // 获取Uri的授权方标识
                String uriAuthority = uri.getAuthority();

                if (isMediaDoc(uriAuthority)) {
                    // 媒体库提供的文档
                    String idArr[] = documentId.split(":");
                    if (idArr.length == 2) {
                        String docType = idArr[0];
                        String realDocId = idArr[1];
                        Uri mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                        if ("image".equals(docType)) {
                            mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                        } else if ("video".equals(docType)) {
                            mediaContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                        } else if ("audio".equals(docType)) {
                            mediaContentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                        }
                        String whereClause = MediaStore.Images.Media._ID + " = " + realDocId;
                        ret = getRealPath(ctx.getContentResolver(), mediaContentUri, whereClause);
                    }

                } else if (isDownloadDoc(uriAuthority)) {
                    // 下载库提供的文档
                    Uri downloadUri = Uri.parse("content://downloads/public_downloads");
                    Uri downloadUriAppendId = ContentUris.withAppendedId(downloadUri, Long.valueOf(documentId));
                    ret = getRealPath(ctx.getContentResolver(), downloadUriAppendId, null);

                } else if (isExternalStoreDoc(uriAuthority)) {
                    // 外部存储提供的文档
                    String idArr[] = documentId.split(":");
                    if (idArr.length == 2) {
                        String type = idArr[0];
                        String realDocId = idArr[1];
                        if ("primary".equalsIgnoreCase(type)) {
                            ret = Environment.getExternalStorageDirectory() + "/" + realDocId;
                        }
                    }
                }
            }
        }
        return ret;
    }

    /* 检查Uri是否为文档类型Uri */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private static boolean isDocumentUri(Context ctx, Uri uri) {
        boolean ret = false;
        if (ctx != null && uri != null) {
            ret = DocumentsContract.isDocumentUri(ctx, uri);
        }
        return ret;
    }

    /* 检查Uri是否为Content类型Uri,示例格式:content://media/external/images/media/1302716 */
    private static boolean isContentUri(Uri uri) {
        boolean ret = false;
        if (uri != null) {
            String uriSchema = uri.getScheme();
            if ("content".equalsIgnoreCase(uriSchema)) {
                ret = true;
            }
        }
        return ret;
    }

    /* 检查Uri是否为File类型Uri,示例格式:file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg */
    private static boolean isFileUri(Uri uri) {
        boolean ret = false;
        if (uri != null) {
            String uriSchema = uri.getScheme();
            if ("file".equalsIgnoreCase(uriSchema)) {
                ret = true;
            }
        }
        return ret;
    }

    /* 检查是否为外部存储提供的文档 */
    private static boolean isExternalStoreDoc(String uriAuthority) {
        return "com.android.externalstorage.documents".equals(uriAuthority);
    }

    /* 检查是否为下载管理提供的文档 */
    private static boolean isDownloadDoc(String uriAuthority) {
        return "com.android.providers.downloads.documents".equals(uriAuthority);
    }

    /* 检查是否为媒体库提供的文档 */
    private static boolean isMediaDoc(String uriAuthority) {
        return "com.android.providers.media.documents".equals(uriAuthority);
    }

    /* 检查是否为谷歌相册提供的文档 */
    private static boolean isGooglePhotoDoc(String uriAuthority) {
        return "com.google.android.apps.photos.content".equals(uriAuthority);
    }

    /* 查询ContentResolver获取Uri对应的真实路径 */
    @SuppressLint("Recycle")
    private static String getRealPath(ContentResolver contentResolver, Uri uri, String whereClause) {
        String ret = "";
        Cursor cursor = contentResolver.query(uri, null, whereClause, null, null);
        if (cursor != null) {
            boolean moveToFirst = cursor.moveToFirst();
            if (moveToFirst) {
                String columnName = MediaStore.Images.Media.DATA;
                if (uri == MediaStore.Images.Media.EXTERNAL_CONTENT_URI) {
                    columnName = MediaStore.Images.Media.DATA;
                } else if (uri == MediaStore.Audio.Media.EXTERNAL_CONTENT_URI) {
                    columnName = MediaStore.Audio.Media.DATA;
                } else if (uri == MediaStore.Video.Media.EXTERNAL_CONTENT_URI) {
                    columnName = MediaStore.Video.Media.DATA;
                }
                int columnIndex = cursor.getColumnIndex(columnName);
                if (columnIndex > -1) {
                    ret = cursor.getString(columnIndex);
                }
                cursor.close();
            }
        }
        return ret;
    }
}

内容的提问来源于stack exchange,提问作者Jairo Daniel Salas Mosquera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:18:01