【问题标题】:How to get the Full file path from URI如何从 URI 获取完整的文件路径
【发布时间】:2012-10-23 22:53:47
【问题描述】:

我想从 URI 获取完整的文件路径。 URI 不是图像,而是音乐文件,但如果我像 MediaStore 解决方案那样做,如果应用程序用户选择例如 Astro 作为浏览器,而不是音乐播放器,它将不起作用。我该如何解决?

【问题讨论】:

    标签: android path get uri


    【解决方案1】:

    PathUtil 方法只能在 oreo 下工作,如果它是 oreo 则可能会崩溃,因为在 oreo 中我们不会获取 id 而是 data.getData() 中的整个路径,所以你需要做的就是从 uri 创建一个文件并从 getPath() 获取其路径并拆分它。下面是工作代码:-

    Uri uri = data.getData(); 
    File file = new File(uri.getPath());//create path from uri
    final String[] split = file.getPath().split(":");//split the path.
    filePath = split[1];//assign it to a string(your choice).
    

    上面的代码可以在 oreo 中运行,如果它低于 oreo 则 PathUtil 可以运行。谢谢!

    String filePath=PathUtil.getPath(context,yourURI);
    

    PathUtil.java

    import android.annotation.SuppressLint; 
    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 java.net.URISyntaxException;
    
    /**
     * Created by Aki on 1/7/2017.
     */
    
    public class PathUtil {
        /*
         * Gets the file path of the given Uri.
         */
        @SuppressLint("NewApi")
        public static String getPath(Context context, Uri uri) throws URISyntaxException {
            final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
            String selection = null;
            String[] selectionArgs = null;
            // Uri is different in versions after KITKAT (Android 4.4), we need to
            // deal with different Uris.
            if (needToCheckUri && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else if (isDownloadsDocument(uri)) {
                    final String id = DocumentsContract.getDocumentId(uri);
                    uri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                } else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
                    if ("image".equals(type)) {
                        uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
                    selection = "_id=?";
                    selectionArgs = new String[]{ split[1] };
                }
            }
            if ("content".equalsIgnoreCase(uri.getScheme())) {
                String[] projection = { MediaStore.Images.Media.DATA };
                Cursor cursor = null;
                try {
                    cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    if (cursor.moveToFirst()) {
                        return cursor.getString(column_index);
                    }
                } catch (Exception e) {
                }
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
            return null;
        }
    
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        public static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        public static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        public static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    }
    

    【讨论】:

    • 仍然给我null。
    • @akhilesh0707 getPath() 将为外部 sdcard 文件返回 null。有什么解决方案吗??
    • 这是最全面的答案,它解释了我能够提出的每一种情况,目前应该是公认的答案
    • 这不适用于 Android 9 上的下载文件:java.lang.IllegalArgumentException: Unknown URI: content://downloads/public_downloads/18
    • 您能否从这些 URI “content://com.android.providers.media.documents/document/document%3A80”(文档)和“content://com.android.providers”中获取路径.downloads.documents/document/msf%3A81"(下载)?
    【解决方案2】:

    当前页面上存在的一个答案 (this) 是正确的,但有一些错误。例如,它不适用于 API 29+ 的设备。 我将更新上面的代码并发布它的新版本。 我认为这篇文章应该被标记为最终答案。

    更新代码:(添加 WhatsApp 支持

    import android.annotation.SuppressLint;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.Intent;
    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.provider.OpenableColumns;
    import android.text.TextUtils;
    import android.util.Log;
    import android.webkit.MimeTypeMap;
    import android.widget.Toast;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FileUtils {
        private static Uri contentUri = null;
    
        Context context;
    
        public FileUtils( Context context) {
            this.context=context;
        }
    
        @SuppressLint("NewApi")
        public static String getPath( final Uri uri) {
            // check here to KITKAT or new version
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            String selection = null;
            String[] selectionArgs = null;
            // DocumentProvider
            if (isKitKat ) {
                // ExternalStorageProvider
    
               if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    String fullPath = getPathFromExtSD(split);
                    if (fullPath != "") {
                        return fullPath;
                    } else {
                        return null;
                    }
                }
    
    
                // DownloadsProvider
    
                if (isDownloadsDocument(uri)) {
    
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        final String id;
                        Cursor cursor = null;
                        try {
                            cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
                            if (cursor != null && cursor.moveToFirst()) {
                                String fileName = cursor.getString(0);
                                String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
                                if (!TextUtils.isEmpty(path)) {
                                    return path;
                                }
                            }
                        }
                        finally {
                            if (cursor != null)
                                cursor.close();
                        }
                        id = DocumentsContract.getDocumentId(uri);
                        if (!TextUtils.isEmpty(id)) {
                            if (id.startsWith("raw:")) {
                                return id.replaceFirst("raw:", "");
                            }
                            String[] contentUriPrefixesToTry = new String[]{
                                    "content://downloads/public_downloads",
                                    "content://downloads/my_downloads"
                            };
                            for (String contentUriPrefix : contentUriPrefixesToTry) {
                                try {
                                    final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
    
    
                                    return getDataColumn(context, contentUri, null, null);
                                } catch (NumberFormatException e) {
                                    //In Android 8 and Android P the id is not a number
                                    return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
                                }
                            }
    
    
                        }
                    }
                    else {
                        final String id = DocumentsContract.getDocumentId(uri);
    
                        if (id.startsWith("raw:")) {
                            return id.replaceFirst("raw:", "");
                        }
                        try {
                            contentUri = ContentUris.withAppendedId(
                                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                        }
                        catch (NumberFormatException e) {
                            e.printStackTrace();
                        }
                        if (contentUri != null) {
    
                            return getDataColumn(context, contentUri, null, null);
                        }
                    }
                }
    
    
                // MediaProvider
               if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final 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;
                    }
                    selection = "_id=?";
                    selectionArgs = new String[]{split[1]};
    
    
                    return getDataColumn(context, contentUri, selection,
                            selectionArgs);
                }
    
               if (isGoogleDriveUri(uri)) {
                    return getDriveFilePath(uri);
                }
    
               if(isWhatsAppFile(uri)){
                    return getFilePathForWhatsApp(uri);
                }
    
    
               if ("content".equalsIgnoreCase(uri.getScheme())) {
    
                    if (isGooglePhotosUri(uri)) {
                        return uri.getLastPathSegment();
                    }
                    if (isGoogleDriveUri(uri)) {
                        return getDriveFilePath(uri);
                    }
                    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                    {
    
                        // return getFilePathFromURI(context,uri);
                        return copyFileToInternalStorage(uri,"userfiles");
                        // return getRealPathFromURI(context,uri);
                    }
                    else
                    {
                        return getDataColumn(context, uri, null, null);
                    }
    
               }
               if ("file".equalsIgnoreCase(uri.getScheme())) {
                    return uri.getPath();
                }
            }
            else {
    
                if(isWhatsAppFile(uri)){
                    return getFilePathForWhatsApp(uri);
                }
    
                if ("content".equalsIgnoreCase(uri.getScheme())) {
                    String[] projection = {
                            MediaStore.Images.Media.DATA
                    };
                    Cursor cursor = null;
                    try {
                        cursor = context.getContentResolver()
                                .query(uri, projection, selection, selectionArgs, null);
                        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                        if (cursor.moveToFirst()) {
                            return cursor.getString(column_index);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
    
    
    
    
            return null;
        }
    
        private  boolean fileExists(String filePath) {
            File file = new File(filePath);
    
            return file.exists();
        }
    
        private String getPathFromExtSD(String[] pathData) {
            final String type = pathData[0];
            final String relativePath = "/" + pathData[1];
            String fullPath = "";
    
            // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
            // something like "71F8-2C0A", some kind of unique id per storage
            // don't know any API that can get the root path of that storage based on its id.
            //
            // so no "primary" type, but let the check here for other devices
            if ("primary".equalsIgnoreCase(type)) {
                fullPath = Environment.getExternalStorageDirectory() + relativePath;
                if (fileExists(fullPath)) {
                    return fullPath;
                }
            }
    
            // Environment.isExternalStorageRemovable() is `true` for external and internal storage
            // so we cannot relay on it.
            //
            // instead, for each possible path, check if file exists
            // we'll start with secondary storage as this could be our (physically) removable sd card
            fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
            if (fileExists(fullPath)) {
                return fullPath;
            }
    
            fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
            if (fileExists(fullPath)) {
                return fullPath;
            }
    
            return fullPath;
        }
    
        private String getDriveFilePath(Uri uri) {
            Uri returnUri = uri;
            Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
            /*
             * Get the column indexes of the data in the Cursor,
             *     * move to the first row in the Cursor, get the data,
             *     * and display it.
             * */
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            String size = (Long.toString(returnCursor.getLong(sizeIndex)));
            File file = new File(context.getCacheDir(), name);
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                FileOutputStream outputStream = new FileOutputStream(file);
                int read = 0;
                int maxBufferSize = 1 * 1024 * 1024;
                int bytesAvailable = inputStream.available();
    
                //int bufferSize = 1024;
                int bufferSize = Math.min(bytesAvailable, maxBufferSize);
    
                final byte[] buffers = new byte[bufferSize];
                while ((read = inputStream.read(buffers)) != -1) {
                    outputStream.write(buffers, 0, read);
                }
                Log.e("File Size", "Size " + file.length());
                inputStream.close();
                outputStream.close();
                Log.e("File Path", "Path " + file.getPath());
                Log.e("File Size", "Size " + file.length());
            } catch (Exception e) {
                Log.e("Exception", e.getMessage());
            }
            return file.getPath();
        }
    
        /***
         * Used for Android Q+
         * @param uri
         * @param newDirName if you want to create a directory, you can set this variable
         * @return
         */
        private String copyFileToInternalStorage(Uri uri,String newDirName) {
            Uri returnUri = uri;
    
            Cursor returnCursor = context.getContentResolver().query(returnUri, new String[]{
                    OpenableColumns.DISPLAY_NAME,OpenableColumns.SIZE
            }, null, null, null);
    
    
            /*
             * Get the column indexes of the data in the Cursor,
             *     * move to the first row in the Cursor, get the data,
             *     * and display it.
             * */
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            String size = (Long.toString(returnCursor.getLong(sizeIndex)));
    
            File output;
            if(!newDirName.equals("")) {
                File dir = new File(context.getFilesDir() + "/" + newDirName);
                if (!dir.exists()) {
                    dir.mkdir();
                }
                output = new File(context.getFilesDir() + "/" + newDirName + "/" + name);
            }
            else{
                output = new File(context.getFilesDir() + "/" + name);
            }
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                FileOutputStream outputStream = new FileOutputStream(output);
                int read = 0;
                int bufferSize = 1024;
                final byte[] buffers = new byte[bufferSize];
                while ((read = inputStream.read(buffers)) != -1) {
                    outputStream.write(buffers, 0, read);
                }
    
                inputStream.close();
                outputStream.close();
    
            }
            catch (Exception e) {
    
                Log.e("Exception", e.getMessage());
            }
    
            return output.getPath();
        }
    
        private String getFilePathForWhatsApp(Uri uri){
                return  copyFileToInternalStorage(uri,"whatsapp");
        }
    
        private 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 index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(index);
                }
            }
            finally {
                if (cursor != null)
                    cursor.close();
            }
    
            return null;
        }
    
        private  boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        private  boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        private  boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        private  boolean isGooglePhotosUri(Uri uri) {
            return "com.google.android.apps.photos.content".equals(uri.getAuthority());
        }
    
        public boolean isWhatsAppFile(Uri uri){
            return "com.whatsapp.provider.media".equals(uri.getAuthority());
        }
    
        private  boolean isGoogleDriveUri(Uri uri) {
            return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
        }
    
    
    }
    

    【讨论】:

    • 您尝试过使用新的谷歌照片应用吗?它不工作。
    • 你是我的英雄
    • 谢谢伙计。你是生命的救星。但我建议您将其保留在 Github 的公共要点中。这样我们就可以轻松地为关注更新添加书签
    • 考虑将其作为库发布到 Github。我发现它是从 Android 4 到 10 最一致的
    • 这个解决方案对我很有效,尤其是从 WhatsApp 等其他非图库应用接收图片时
    【解决方案3】:

    用途:

    String path = yourAndroidURI.uri.getPath() // "/mnt/sdcard/FileName.mp3"
    File file = new File(new URI(path));
    

    String path = yourAndroidURI.uri.toString() // "file:///mnt/sdcard/FileName.mp3"
    File file = new File(new URI(path));
    

    【讨论】:

    • 构造函数 File(URI) 未定义?
    • 在我的机器上,Uri::getPath 的结果会以“/”开头,而 Uri::toString() 的结果会以“file://”开头。
    • 这个答案是有害的,不值得它获得的选票。如果 Uri 是 content:// 或任何其他非文件 Uri,则会失败。
    • 引起:java.lang.IllegalArgumentException:URI 不是绝对的
    • 我不明白为什么这仍然是公认的答案。它现在根本行不通。
    【解决方案4】:

    从 URI 获取路径 使用下面的类用于 android 所有版本。 访问任何类型的文件

    package com.satya.filemangerdemo.common;
    
    import android.annotation.SuppressLint;
    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.provider.OpenableColumns;
    import android.text.TextUtils;
    import android.util.Log;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.util.List;
    
    public class FileUtils {
        private static Uri contentUri = null;
    
        /**
         * Get a file path from a Uri. This will get the the path for Storage Access
         * Framework Documents, as well as the _data field for the MediaStore and
         * other file-based ContentProviders.<br>
         * <br>
         * Callers should check whether the path is local before assuming it
         * represents a local file.
         *
         * @param context The context.
         * @param uri     The Uri to query.
         */
        @SuppressLint("NewApi")
        public static String getPath(final Context context, final Uri uri) {
            // check here to KITKAT or new version
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            String selection = null;
            String[] selectionArgs = null;
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    String fullPath = getPathFromExtSD(split);
                    if (fullPath != "") {
                        return fullPath;
                    } else {
                        return null;
                    }
                }
    
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        final String id;
                        Cursor cursor = null;
                        try {
                            cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
                            if (cursor != null && cursor.moveToFirst()) {
                                String fileName = cursor.getString(0);
                                String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
                                if (!TextUtils.isEmpty(path)) {
                                    return path;
                                }
                            }
                        } finally {
                            if (cursor != null)
                                cursor.close();
                        }
                        id = DocumentsContract.getDocumentId(uri);
                        if (!TextUtils.isEmpty(id)) {
                            if (id.startsWith("raw:")) {
                                return id.replaceFirst("raw:", "");
                            }
                            String[] contentUriPrefixesToTry = new String[]{
                                    "content://downloads/public_downloads",
                                    "content://downloads/my_downloads"
                            };
                            for (String contentUriPrefix : contentUriPrefixesToTry) {
                                try {
                                    final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
    
                             /*   final Uri contentUri = ContentUris.withAppendedId(
                                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));*/
    
                                    return getDataColumn(context, contentUri, null, null);
                                } catch (NumberFormatException e) {
                                    //In Android 8 and Android P the id is not a number
                                    return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
                                }
                            }
    
    
                        }
    
                    } else {
                        final String id = DocumentsContract.getDocumentId(uri);
                        final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
                        if (id.startsWith("raw:")) {
                            return id.replaceFirst("raw:", "");
                        }
                        try {
                            contentUri = ContentUris.withAppendedId(
                                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                        } catch (NumberFormatException e) {
                            e.printStackTrace();
                        }
                        if (contentUri != null) {
                            return getDataColumn(context, contentUri, null, null);
                        }
                    }
    
    
                }
                // MediaProvider
                else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final 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;
                    }
                      selection = "_id=?";
                     selectionArgs = new String[]{split[1]};
    
    
                    return getDataColumn(context, contentUri, selection,
                            selectionArgs);
                } else if (isGoogleDriveUri(uri)) {
                    return getDriveFilePath(uri, context);
                }
            }
    
    
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
    
                if (isGooglePhotosUri(uri)) {
                    return uri.getLastPathSegment();
                }
    
                if (isGoogleDriveUri(uri)) {
                    return getDriveFilePath(uri, context);
                }
                 if( Build.VERSION.SDK_INT == Build.VERSION_CODES.N)
                 {
                    // return getFilePathFromURI(context,uri);
                     return getMediaFilePathForN(uri, context);
                    // return getRealPathFromURI(context,uri);
                 }else
                 {
    
                     return getDataColumn(context, uri, null, null);
                 }
    
    
            }
            // File
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
    
            return null;
        }
    
        /**
         * Check if a file exists on device
         *
         * @param filePath The absolute file path
         */
        private static boolean fileExists(String filePath) {
            File file = new File(filePath);
    
            return file.exists();
        }
    
    
        /**
         * Get full file path from external storage
         *
         * @param pathData The storage type and the relative path
         */
        private static String getPathFromExtSD(String[] pathData) {
            final String type = pathData[0];
            final String relativePath = "/" + pathData[1];
            String fullPath = "";
    
            // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
            // something like "71F8-2C0A", some kind of unique id per storage
            // don't know any API that can get the root path of that storage based on its id.
            //
            // so no "primary" type, but let the check here for other devices
            if ("primary".equalsIgnoreCase(type)) {
                fullPath = Environment.getExternalStorageDirectory() + relativePath;
                if (fileExists(fullPath)) {
                    return fullPath;
                }
            }
    
            // Environment.isExternalStorageRemovable() is `true` for external and internal storage
            // so we cannot relay on it.
            //
            // instead, for each possible path, check if file exists
            // we'll start with secondary storage as this could be our (physically) removable sd card
            fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
            if (fileExists(fullPath)) {
                return fullPath;
            }
    
            fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
            if (fileExists(fullPath)) {
                return fullPath;
            }
    
            return fullPath;
        }
    
        private static String getDriveFilePath(Uri uri, Context context) {
            Uri returnUri = uri;
            Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
            /*
             * Get the column indexes of the data in the Cursor,
             *     * move to the first row in the Cursor, get the data,
             *     * and display it.
             * */
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            String size = (Long.toString(returnCursor.getLong(sizeIndex)));
            File file = new File(context.getCacheDir(), name);
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                FileOutputStream outputStream = new FileOutputStream(file);
                int read = 0;
                int maxBufferSize = 1 * 1024 * 1024;
                int bytesAvailable = inputStream.available();
    
                //int bufferSize = 1024;
                int bufferSize = Math.min(bytesAvailable, maxBufferSize);
    
                final byte[] buffers = new byte[bufferSize];
                while ((read = inputStream.read(buffers)) != -1) {
                    outputStream.write(buffers, 0, read);
                }
                Log.e("File Size", "Size " + file.length());
                inputStream.close();
                outputStream.close();
                Log.e("File Path", "Path " + file.getPath());
                Log.e("File Size", "Size " + file.length());
            } catch (Exception e) {
                Log.e("Exception", e.getMessage());
            }
            return file.getPath();
        }
    
        private static String getMediaFilePathForN(Uri uri, Context context) {
            Uri returnUri = uri;
            Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
            /*
             * Get the column indexes of the data in the Cursor,
             *     * move to the first row in the Cursor, get the data,
             *     * and display it.
             * */
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            String size = (Long.toString(returnCursor.getLong(sizeIndex)));
            File file = new File(context.getFilesDir(), name);
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                FileOutputStream outputStream = new FileOutputStream(file);
                int read = 0;
                int maxBufferSize = 1 * 1024 * 1024;
                int bytesAvailable = inputStream.available();
    
                //int bufferSize = 1024;
                int bufferSize = Math.min(bytesAvailable, maxBufferSize);
    
                final byte[] buffers = new byte[bufferSize];
                while ((read = inputStream.read(buffers)) != -1) {
                    outputStream.write(buffers, 0, read);
                }
                Log.e("File Size", "Size " + file.length());
                inputStream.close();
                outputStream.close();
                Log.e("File Path", "Path " + file.getPath());
                Log.e("File Size", "Size " + file.length());
            } catch (Exception e) {
                Log.e("Exception", e.getMessage());
            }
            return file.getPath();
        }
    
    
        private static 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 index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(index);
                }
            } finally {
                if (cursor != null)
                    cursor.close();
            }
    
            return null;
        }
    
        /**
         * @param uri - The Uri to check.
         * @return - Whether the Uri authority is ExternalStorageProvider.
         */
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri - The Uri to check.
         * @return - Whether the Uri authority is DownloadsProvider.
         */
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri - The Uri to check.
         * @return - Whether the Uri authority is MediaProvider.
         */
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri - The Uri to check.
         * @return - Whether the Uri authority is Google Photos.
         */
        private static boolean isGooglePhotosUri(Uri uri) {
            return "com.google.android.apps.photos.content".equals(uri.getAuthority());
        }
    
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Drive.
         */
        private static boolean isGoogleDriveUri(Uri uri) {
            return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
        }
    
    
    }
    

    但现在根据 android 最新指南,您无法直接访问 getExternalStorageDirectory()。您需要为此实施解决方法

    【讨论】:

    【解决方案5】:

    试试这个。

    public String getRealPathFromURI(Uri contentUri) 
    {
         String[] proj = { MediaStore.Audio.Media.DATA };
         Cursor cursor = managedQuery(contentUri, proj, null, null, null);
         int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
         cursor.moveToFirst();
         return cursor.getString(column_index);
    }
    

    【讨论】:

    【解决方案6】:

    您可以使用从不同的 SDK 版本获取文件路径

    为此使用 RealPathUtils

    public class RealPathUtils {
    
    @SuppressLint("NewApi")
    public static String getRealPathFromURI_API19(Context context, Uri uri){
        String filePath = "";
        String wholeID = DocumentsContract.getDocumentId(uri);
    
        // Split at colon, use second item in the array
        String id = wholeID.split(":")[1];
    
        String[] column = { MediaStore.Images.Media.DATA };
    
        // where id is equal to
        String sel = MediaStore.Images.Media._ID + "=?";
    
        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                column, sel, new String[]{ id }, null);
    
        int columnIndex = cursor.getColumnIndex(column[0]);
    
        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();
        return filePath;
    }
    
    
    @SuppressLint("NewApi")
    public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
        String[] proj = { MediaStore.Images.Media.DATA };
        String result = null;
    
        CursorLoader cursorLoader = new CursorLoader(
                context,
                contentUri, proj, null, null, null);
        Cursor cursor = cursorLoader.loadInBackground();
    
        if(cursor != null){
            int column_index =
                    cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            result = cursor.getString(column_index);
        }
        return result;
    }
    
    public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
        String[] proj = { MediaStore.Images.Media.DATA };
        Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        int column_index
                = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }
    }
    

    **现在从 URI 获取文件路径 **

     String path = null;
                    if (Build.VERSION.SDK_INT < 11)
                        path = RealPathUtils.getRealPathFromURI_BelowAPI11(MainActivity.this, uri);
    
                        // SDK >= 11 && SDK < 19
                    else if (Build.VERSION.SDK_INT < 19)
                        path = RealPathUtils.getRealPathFromURI_API11to18(MainActivity.this, uri);
    
                        // SDK > 19 (Android 4.4)
                    else
                        path = RealPathUtils.getRealPathFromURI_API19(MainActivity.this, uri);
                    Log.d(TAG, "File Path: " + path);
                    // Get the file instance
                     File file = new File(path);
    

    【讨论】:

    • 这仅适用于 MediaStore.Images.Media 。如果您想获取其他文件,而不能与 MediaStore.FileColumns 一起使用,我将展示该过程!
    • 这是完美的解决方案
    【解决方案7】:
    package com.utils;
    
    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.support.annotation.RequiresApi;
    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 {
    
        /* Get uri related content real local file path. */
        public static String getPath(Context ctx, Uri uri) {
            String ret;
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    // Android OS above sdk version 19.
                    ret = getUriRealPathAboveKitkat(ctx, uri);
                } else {
                    // Android OS below sdk version 19
                    ret = getRealPath(ctx.getContentResolver(), uri, null);
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.d("DREG", "FilePath Catch: " + e);
                ret = getFilePathFromURI(ctx, uri);
            }
            return ret;
        }
    
        private static String getFilePathFromURI(Context context, Uri contentUri) {
            //copy file and send new file path
            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", "FilePath copyFile: " + copyFile);
                copy(context, contentUri, copyFile);
                return copyFile.getAbsolutePath();
            }
            return null;
        }
    
        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;
        }
    
        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.copyStream(inputStream, outputStream); // org.apache.commons.io
                inputStream.close();
                outputStream.close();
            } catch (Exception e) { // IOException
                e.printStackTrace();
            }
        }
    
        @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)) {
    
                    // Get uri related document id.
                    String documentId = DocumentsContract.getDocumentId(uri);
    
                    // Get uri authority.
                    String uriAuthority = uri.getAuthority();
    
                    if (isMediaDoc(uriAuthority)) {
                        String idArr[] = documentId.split(":");
                        if (idArr.length == 2) {
                            // First item is document type.
                            String docType = idArr[0];
    
                            // Second item is document real id.
                            String realDocId = idArr[1];
    
                            // Get content uri by document type.
                            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;
                            }
    
                            // Get where clause with real document id.
                            String whereClause = MediaStore.Images.Media._ID + " = " + realDocId;
    
                            ret = getRealPath(ctx.getContentResolver(), mediaContentUri, whereClause);
                        }
    
                    } else if (isDownloadDoc(uriAuthority)) {
                        // Build download uri.
                        Uri downloadUri = Uri.parse("content://downloads/public_downloads");
    
                        // Append download document id at uri end.
                        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;
        }
    
        /* Check whether this uri represent a document or not. */
        @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;
        }
    
        /* Check whether this uri is a content uri or not.
         *  content uri like 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;
        }
    
        /* Check whether this uri is a file uri or not.
         *  file uri like 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;
        }
    
        /* Check whether this document is provided by ExternalStorageProvider. */
        private static boolean isExternalStoreDoc(String uriAuthority) {
            boolean ret = false;
    
            if ("com.android.externalstorage.documents".equals(uriAuthority)) {
                ret = true;
            }
    
            return ret;
        }
    
        /* Check whether this document is provided by DownloadsProvider. */
        private static boolean isDownloadDoc(String uriAuthority) {
            boolean ret = false;
    
            if ("com.android.providers.downloads.documents".equals(uriAuthority)) {
                ret = true;
            }
    
            return ret;
        }
    
        /* Check whether this document is provided by MediaProvider. */
        private static boolean isMediaDoc(String uriAuthority) {
            boolean ret = false;
    
            if ("com.android.providers.media.documents".equals(uriAuthority)) {
                ret = true;
            }
    
            return ret;
        }
    
        /* Check whether this document is provided by google photos. */
        private static boolean isGooglePhotoDoc(String uriAuthority) {
            boolean ret = false;
    
            if ("com.google.android.apps.photos.content".equals(uriAuthority)) {
                ret = true;
            }
    
            return ret;
        }
    
        /* Return uri represented document file real local path.*/
        @SuppressLint("Recycle")
        private static String getRealPath(ContentResolver contentResolver, Uri uri, String whereClause) {
            String ret = "";
    
            // Query the uri with condition.
            Cursor cursor = contentResolver.query(uri, null, whereClause, null, null);
    
            if (cursor != null) {
                boolean moveToFirst = cursor.moveToFirst();
                if (moveToFirst) {
    
                    // Get columns name by uri type.
                    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;
                    }
    
                    // Get column index.
                    int columnIndex = cursor.getColumnIndex(columnName);
    
                    // Get column value which is the uri related file local path.
                    ret = cursor.getString(columnIndex);
                }
            }
    
            return ret;
        }
    
    }
    

    在 build.gradle 文件中 添加这个

    implementation 'org.apache.commons:commons-lang3:3.4'
    

    现在从你的主班呼叫FileUtils.getPath(context, uri);

    【讨论】:

    • 此解决方案适用于为所有共享存储文件夹选择文件。我正在上传到 Firebase 存储并尝试了所有其他解决方案,但是当您从其他位置选择文件时,它们会导致 FileNotFoundException。这完美无缺
    【解决方案8】:

    我知道这已经得到解答。但是我在 cmets 中发现了一些问题。我从here 中找到了一个非常可靠的解决方案@

    使用它 File file=FileUtils.getFile(uri);

    public class FileUtils {
    
    //replace this with your authority
    public static final String AUTHORITY = "com.ianhanniballake.localstorage.documents";
    
    
    private FileUtils() {
    } //private constructor to enforce Singleton pattern
    
    /**
     * TAG for log messages.
     */
    static final String TAG = "FileUtils";
    private static final boolean DEBUG = false; // Set to true to enable logging
    
    
    /**
     * @return Whether the URI is a local one.
     */
    public static boolean isLocal(String url) {
        if (url != null && !url.startsWith("http://") && !url.startsWith("https://")) {
            return true;
        }
        return false;
    }
    
    
    public static boolean isLocalStorageDocument(Uri uri) {
        return AUTHORITY.equals(uri.getAuthority());
    }
    
    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     * @author paulburke
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }
    
    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     * @author paulburke
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }
    
    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     * @author paulburke
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }
    
    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri.getAuthority());
    }
    
    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     * @author paulburke
     */
    public static 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()) {
                if (DEBUG)
                    DatabaseUtils.dumpCursor(cursor);
    
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }
    
    /**
     * Get a file path from a Uri. This will get the the path for Storage Access
     * Framework Documents, as well as the _data field for the MediaStore and
     * other file-based ContentProviders.<br>
     * <br>
     * Callers should check whether the path is local before assuming it
     * represents a local file.
     *
     * @param context The context.
     * @param uri     The Uri to query.
     * @author paulburke
     * @see #isLocal(String)
     * @see #getFile(Context, Uri)
     */
    public static String getPath(final Context context, final Uri uri) {
    
    
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    
        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // LocalStorageProvider
            if (isLocalStorageDocument(uri)) {
                // The path is the id
                return DocumentsContract.getDocumentId(uri);
            }
            // ExternalStorageProvider
            else if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
    
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }
    
                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
    
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final 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;
                }
    
                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };
    
                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
    
            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();
    
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
    
        return null;
    }
    
    /**
     * Convert Uri into File, if possible.
     *
     * @return file A local file that the Uri was pointing to, or null if the
     * Uri is unsupported or pointed to a remote resource.
     * @author paulburke
     * @see #getPath(Context, Uri)
     */
    public static File getFile(Context context, Uri uri) {
        if (uri != null) {
            String path = getPath(context, uri);
            if (path != null && isLocal(path)) {
                return new File(path);
            }
        }
        return null;
      }
    
    
    }
    

    【讨论】:

    • 感谢它的工作原理,但在外部存储器上没有得到 Android L 的完美路径
    • 我没有添加完整的课程。检查链接并使用完整的课程。我相信它会解决你的问题。
    • 是的,我也尝试过,但结果相同:(
    • 当文件在外部 SD 卡上时,这似乎失败了(返回空值)。任何解决方案?
    • @Snake 你找到解决办法了吗?
    【解决方案9】:

    您可以使用此功能从新 android 和旧版本的 uri 中获取文件

    fun getFileFromUri(uri: Uri): File? {
        if (uri.path == null) {
            return null
        }
        var realPath = String()
        val databaseUri: Uri
        val selection: String?
        val selectionArgs: Array<String>?
        if (uri.path!!.contains("/document/image:")) {
            databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            selection = "_id=?"
            selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
        } else {
            databaseUri = uri
            selection = null
            selectionArgs = null
        }
        try {
            val column = "_data"
            val projection = arrayOf(column)
            val cursor = context.contentResolver.query(
                databaseUri,
                projection,
                selection,
                selectionArgs,
                null
            )
            cursor?.let {
                if (it.moveToFirst()) {
                    val columnIndex = cursor.getColumnIndexOrThrow(column)
                    realPath = cursor.getString(columnIndex)
                }
                cursor.close()
            }
        } catch (e: Exception) {
            Log.i("GetFileUri Exception:", e.message ?: "")
        }
        val path = if (realPath.isNotEmpty()) realPath else {
            when {
                uri.path!!.contains("/document/raw:") -> uri.path!!.replace(
                    "/document/raw:",
                    ""
                )
                uri.path!!.contains("/document/primary:") -> uri.path!!.replace(
                    "/document/primary:",
                    "/storage/emulated/0/"
                )
                else -> return null
            }
        }
        return File(path)
    }
    

    【讨论】:

    • 它没有访问下载文件夹中的文件
    • 你能告诉我你的代码吗?我使用此代码,它适用于所有文件夹和所有机器人
    • 下面的 ans (stackoverflow.com/a/55469368/9764941) 对我有用。谢谢
    【解决方案10】:

    收到文件路径时的代码片段。

     Uri fileUri = data.getData();
     FilePathHelper filePathHelper = new FilePathHelper();
     String path = "";
     if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
           if (filePathHelper.getPathnew(fileUri, this) != null) {
                  path = filePathHelper.getPathnew(fileUri, this).toLowerCase();
           } else {
                  path = filePathHelper.getFilePathFromURI(fileUri, this).toLowerCase();
           }
     } else {
           path = filePathHelper.getPath(fileUri, this).toLowerCase();
     }
    

    Bellow 是一个可以通过创建新对象来访问的类。您还需要在gradel implementation 'org.apache.directory.studio:org.apache.commons.io:2.4'中添加一个依赖项

    public class FilePathHelper {
    
        public FilePathHelper(){
    
        }
    
        public String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url.replace(" ", ""));
            if (extension != null) {
                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }
            return type;
        }
    
        public String getFilePathFromURI(Uri contentUri, Context context) {
            //copy file and send new file path
            String fileName = getFileName(contentUri);
            if (!TextUtils.isEmpty(fileName)) {
                File copyFile = new File(context.getExternalCacheDir() + File.separator + fileName);
                copy(context, contentUri, copyFile);
                return copyFile.getAbsolutePath();
            }
            return null;
        }
    
        public 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 (IOException e) {
                e.printStackTrace();
            }
        }
    
        public String getPath(Uri uri, Context context) {
            String filePath = null;
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            if (isKitKat) {
                filePath = generateFromKitkat(uri, context);
            }
    
            if (filePath != null) {
                return filePath;
            }
    
            Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DATA}, null, null, null);
    
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                    filePath = cursor.getString(columnIndex);
                }
                cursor.close();
            }
            return filePath == null ? uri.getPath() : filePath;
        }
    
        @TargetApi(19)
        private String generateFromKitkat(Uri uri, Context context) {
            String filePath = null;
            if (DocumentsContract.isDocumentUri(context, uri)) {
                String wholeID = DocumentsContract.getDocumentId(uri);
    
                String id = wholeID.split(":")[1];
    
                String[] column = {MediaStore.Video.Media.DATA};
                String sel = MediaStore.Video.Media._ID + "=?";
    
                Cursor cursor = context.getContentResolver().
                        query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                                column, sel, new String[]{id}, null);
    
    
                int columnIndex = cursor.getColumnIndex(column[0]);
    
                if (cursor.moveToFirst()) {
                    filePath = cursor.getString(columnIndex);
                }
    
                cursor.close();
            }
            return filePath;
        }
    
        public 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;
        }
    
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        public String getPathnew(Uri uri, Context context) {
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    if ("primary".equalsIgnoreCase(type)) {
                        return Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                    // TODO handle non-primary volumes
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
                    final String id = DocumentsContract.getDocumentId(uri);
                    final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                    return getDataColumn(context, contentUri, null, null);
                }
                // MediaProvider
                else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final 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;
                    }
                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{split[1]};
                    return getDataColumn(context, contentUri, selection, selectionArgs);
                }
            }
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
                // Return the remote address
                if (isGooglePhotosUri(uri))
                    return uri.getLastPathSegment();
                return getDataColumn(context, uri, null, null);
            }
            // File
            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 index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(index);
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("Something with exception - " + e.toString());
            } finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
    
        public boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        public boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        public boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        public boolean isGooglePhotosUri(Uri uri) {
            return "com.google.android.apps.photos.content".equals(uri.getAuthority());
        }
    }
    

    【讨论】:

    • 你应该在filePathHelper中添加对SDK的检查
    【解决方案11】:
      public String getPath(Uri uri) {
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        cursor.moveToFirst();
        String document_id = cursor.getString(0);
        document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
        cursor.close();
    
        cursor = getContentResolver().query(
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
        cursor.moveToFirst();
        String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
    
        return path;
    }
    

    使用这种方法我们可以从 Uri 中获取字符串文件路径。

    【讨论】:

    • 我希望如此,不要确认,因为这是我在 2020 年所做的并且工作得非常好。
    • 它仅在您从最近的图像中选择图像时才有效,并且在您尝试从任何文件夹获取路径时总是崩溃
    • 我搬到了颤振,所以我可能无法进一步帮助你,但如果你真的需要这个,请告诉我。
    【解决方案12】:

    要获取任何类型的文件路径,请使用此(取自https://github.com/iPaulPro/aFileChooser

    package com.yourpackage;
    
    import android.content.ContentResolver;
    import android.content.ContentUris;
    import android.content.Context;
    import android.content.Intent;
    import android.database.Cursor;
    import android.database.DatabaseUtils;
    import android.graphics.Bitmap;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    import android.util.Log;
    import android.webkit.MimeTypeMap;
    
    import java.io.File;
    import java.io.FileFilter;
    import java.text.DecimalFormat;
    import java.util.Comparator;
    import java.util.List;
    
    /**
     * @author Peli
     * @author paulburke (ipaulpro)
     * @version 2013-12-11
     */
    public class FileUtils {
        private FileUtils() {
        } //private constructor to enforce Singleton pattern
    
        /**
         * TAG for log messages.
         */
        static final String TAG = "FileUtils";
        private static final boolean DEBUG = true; // Set to true to enable logging
    
        public static final String MIME_TYPE_AUDIO = "audio/*";
        public static final String MIME_TYPE_TEXT = "text/*";
        public static final String MIME_TYPE_IMAGE = "image/*";
        public static final String MIME_TYPE_VIDEO = "video/*";
        public static final String MIME_TYPE_APP = "application/*";
    
        public static final String HIDDEN_PREFIX = ".";
    
        /**
         * Gets the extension of a file name, like ".png" or ".jpg".
         *
         * @param uri
         * @return Extension including the dot("."); "" if there is no extension;
         * null if uri was null.
         */
        public static String getExtension(String uri) {
            if (uri == null) {
                return null;
            }
    
            int dot = uri.lastIndexOf(".");
            if (dot >= 0) {
                return uri.substring(dot);
            } else {
                // No extension.
                return "";
            }
        }
    
        /**
         * @return Whether the URI is a local one.
         */
        public static boolean isLocal(String url) {
            if (url != null && !url.startsWith("http://") && !url.startsWith("https://")) {
                return true;
            }
            return false;
        }
    
        /**
         * @return True if Uri is a MediaStore Uri.
         * @author paulburke
         */
        public static boolean isMediaUri(Uri uri) {
            return "media".equalsIgnoreCase(uri.getAuthority());
        }
    
        /**
         * Convert File into Uri.
         *
         * @param file
         * @return uri
         */
        public static Uri getUri(File file) {
            if (file != null) {
                return Uri.fromFile(file);
            }
            return null;
        }
    
        /**
         * Returns the path only (without file name).
         *
         * @param file
         * @return
         */
        public static File getPathWithoutFilename(File file) {
            if (file != null) {
                if (file.isDirectory()) {
                    // no file to be split off. Return everything
                    return file;
                } else {
                    String filename = file.getName();
                    String filepath = file.getAbsolutePath();
    
                    // Construct path without file name.
                    String pathwithoutname = filepath.substring(0,
                            filepath.length() - filename.length());
                    if (pathwithoutname.endsWith("/")) {
                        pathwithoutname = pathwithoutname.substring(0, pathwithoutname.length() - 1);
                    }
                    return new File(pathwithoutname);
                }
            }
            return null;
        }
    
        /**
         * @return The MIME type for the given file.
         */
        public static String getMimeType(File file) {
    
            String extension = getExtension(file.getName());
    
            if (extension.length() > 0)
                return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
    
            return "application/octet-stream";
        }
    
        /**
         * @return The MIME type for the give Uri.
         */
        public static String getMimeType(Context context, Uri uri) {
            File file = new File(getPath(context, uri));
            return getMimeType(file);
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is {@link LocalStorageProvider}.
         * @author paulburke
         */
        public static boolean isLocalStorageDocument(Uri uri) {
            return LocalStorageProvider.AUTHORITY.equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         * @author paulburke
         */
        public static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         * @author paulburke
         */
        public static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         * @author paulburke
         */
        public static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        public static boolean isGooglePhotosUri(Uri uri) {
            return "com.google.android.apps.photos.content".equals(uri.getAuthority());
        }
    
        /**
         * Get the value of the data column for this Uri. This is useful for
         * MediaStore Uris, and other file-based ContentProviders.
         *
         * @param context       The context.
         * @param uri           The Uri to query.
         * @param selection     (Optional) Filter used in the query.
         * @param selectionArgs (Optional) Selection arguments used in the query.
         * @return The value of the _data column, which is typically a file path.
         * @author paulburke
         */
        public static 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()) {
                    if (DEBUG)
                        DatabaseUtils.dumpCursor(cursor);
    
                    final int column_index = cursor.getColumnIndexOrThrow(column);
                    return cursor.getString(column_index);
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if (cursor != null)
                    cursor.close();
            }
            return null;
        }
    
        /**
         * Get a file path from a Uri. This will quickGet the the path for Storage Access
         * Framework Documents, as well as the _data field for the MediaStore and
         * other file-based ContentProviders.<br>
         * <br>
         * Callers should check whether the path is local before assuming it
         * represents a local file.
         *
         * @param context The context.
         * @param uri     The Uri to query.
         * @author paulburke
         * @see #isLocal(String)
         * @see #getFile(Context, Uri)
         */
        public static String getPath(final Context context, final Uri uri) {
    
            if (DEBUG)
                Log.d(TAG + " File -",
                        "Authority: " + uri.getAuthority() +
                                ", Fragment: " + uri.getFragment() +
                                ", Port: " + uri.getPort() +
                                ", Query: " + uri.getQuery() +
                                ", Scheme: " + uri.getScheme() +
                                ", Host: " + uri.getHost() +
                                ", Segments: " + uri.getPathSegments().toString()
                );
            // DocumentProvider
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
                // LocalStorageProvider
                if (isLocalStorageDocument(uri)) {
                    // The path is the id
                    return DocumentsContract.getDocumentId(uri);
                }
                // ExternalStorageProvider
                else if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
    //                if ("primary".equalsIgnoreCase(type)) {
    //                    return Environment.getExternalStorageDirectory() + "/" + split[1];
    //                }
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
    
                    // TODO handle non-primary volumes
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
                    try {
                        final String id = DocumentsContract.getDocumentId(uri);
                        Log.d(TAG, "getPath: id= " + id);
                        final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                        return getDataColumn(context, contentUri, null, null);
                    }catch (Exception e){
                        e.printStackTrace();
                        List<String> segments = uri.getPathSegments();
                        if(segments.size() > 1) {
                            String rawPath = segments.get(1);
                            if(!rawPath.startsWith("/")){
                                return rawPath.substring(rawPath.indexOf("/"));
                            }else {
                                return rawPath;
                            }
                        }
                    }
                }
                // MediaProvider
                else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final 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;
                    }
    
                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{
                            split[1]
                    };
    
                    return getDataColumn(context, contentUri, selection, selectionArgs);
                }
            }
            // MediaStore (and general)
            else if ("content".equalsIgnoreCase(uri.getScheme())) {
    
                // Return the remote address
                if (isGooglePhotosUri(uri))
                    return uri.getLastPathSegment();
    
                return getDataColumn(context, uri, null, null);
            }
            // File
            else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
    
            return null;
        }
    
        /**
         * Convert Uri into File, if possible.
         *
         * @return file A local file that the Uri was pointing to, or null if the
         * Uri is unsupported or pointed to a remote resource.
         * @author paulburke
         * @see #getPath(Context, Uri)
         */
        public static File getFile(Context context, Uri uri) {
            if (uri != null) {
                String path = getPath(context, uri);
                if (path != null && isLocal(path)) {
                    return new File(path);
                }
            }
            return null;
        }
    
        /**
         * Get the file size in a human-readable string.
         *
         * @param size
         * @return
         * @author paulburke
         */
        public static String getReadableFileSize(int size) {
            final int BYTES_IN_KILOBYTES = 1024;
            final DecimalFormat dec = new DecimalFormat("###.#");
            final String KILOBYTES = " KB";
            final String MEGABYTES = " MB";
            final String GIGABYTES = " GB";
            float fileSize = 0;
            String suffix = KILOBYTES;
    
            if (size > BYTES_IN_KILOBYTES) {
                fileSize = size / BYTES_IN_KILOBYTES;
                if (fileSize > BYTES_IN_KILOBYTES) {
                    fileSize = fileSize / BYTES_IN_KILOBYTES;
                    if (fileSize > BYTES_IN_KILOBYTES) {
                        fileSize = fileSize / BYTES_IN_KILOBYTES;
                        suffix = GIGABYTES;
                    } else {
                        suffix = MEGABYTES;
                    }
                }
            }
            return String.valueOf(dec.format(fileSize) + suffix);
        }
    
        /**
         * Attempt to retrieve the thumbnail of given File from the MediaStore. This
         * should not be called on the UI thread.
         *
         * @param context
         * @param file
         * @return
         * @author paulburke
         */
        public static Bitmap getThumbnail(Context context, File file) {
            return getThumbnail(context, getUri(file), getMimeType(file));
        }
    
        /**
         * Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
         * should not be called on the UI thread.
         *
         * @param context
         * @param uri
         * @return
         * @author paulburke
         */
        public static Bitmap getThumbnail(Context context, Uri uri) {
            return getThumbnail(context, uri, getMimeType(context, uri));
        }
    
        /**
         * Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
         * should not be called on the UI thread.
         *
         * @param context
         * @param uri
         * @param mimeType
         * @return
         * @author paulburke
         */
        public static Bitmap getThumbnail(Context context, Uri uri, String mimeType) {
            if (DEBUG)
                Log.d(TAG, "Attempting to quickGet thumbnail");
    
            if (!isMediaUri(uri)) {
                Log.e(TAG, "You can only retrieve thumbnails for images and videos.");
                return null;
            }
    
            Bitmap bm = null;
            if (uri != null) {
                final ContentResolver resolver = context.getContentResolver();
                Cursor cursor = null;
                try {
                    cursor = resolver.query(uri, null, null, null, null);
                    if (cursor.moveToFirst()) {
                        final int id = cursor.getInt(0);
                        if (DEBUG)
                            Log.d(TAG, "Got thumb ID: " + id);
    
                        if (mimeType.contains("video")) {
                            bm = MediaStore.Video.Thumbnails.getThumbnail(
                                    resolver,
                                    id,
                                    MediaStore.Video.Thumbnails.MINI_KIND,
                                    null);
                        } else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE)) {
                            bm = MediaStore.Images.Thumbnails.getThumbnail(
                                    resolver,
                                    id,
                                    MediaStore.Images.Thumbnails.MINI_KIND,
                                    null);
                        }
                    }
                } catch (Exception e) {
                    if (DEBUG)
                        Log.e(TAG, "getThumbnail", e);
                } finally {
                    if (cursor != null)
                        cursor.close();
                }
            }
            return bm;
        }
    
        /**
         * File and folder comparator. TODO Expose sorting option method
         *
         * @author paulburke
         */
        public static Comparator<File> sComparator = new Comparator<File>() {
            @Override
            public int compare(File f1, File f2) {
                // Sort alphabetically by lower case, which is much cleaner
                return f1.getName().toLowerCase().compareTo(
                        f2.getName().toLowerCase());
            }
        };
    
        /**
         * File (not directories) filter.
         *
         * @author paulburke
         */
        public static FileFilter sFileFilter = new FileFilter() {
            @Override
            public boolean accept(File file) {
                final String fileName = file.getName();
                // Return files only (not directories) and skip hidden files
                return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
            }
        };
    
        /**
         * Folder (directories) filter.
         *
         * @author paulburke
         */
        public static FileFilter sDirFilter = new FileFilter() {
            @Override
            public boolean accept(File file) {
                final String fileName = file.getName();
                // Return directories only and skip hidden directories
                return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX);
            }
        };
    
        /**
         * Get the Intent for selecting content to be used in an Intent Chooser.
         *
         * @return The intent for opening a file with Intent.createChooser()
         * @author paulburke
         */
        public static Intent createGetContentIntent() {
            // Implicitly allow the user to select a particular kind of data
            final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            // The MIME data type filter
            intent.setType("*/*");
            // Only return URIs that can be opened with ContentResolver
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            return intent;
        }
    }
    

    【讨论】:

    • @K40S,现在可以从许多来源获得此代码。虽然我从另一个来源获取,但无法记住它。但是,我已在我的解决方案中添加了您的来源。在这方面,被盗是一个严厉的词。
    • 在没有信用的情况下采取,而违反许可条款(将许可附加到代码)是在窃取。我不想羞辱你什么的,只是想用正确的词:)
    • 如果您看到粘贴的代码,您会看到与真实作者相关的所有 cmets 都不会从该答案中删除。我故意保留它,很抱歉没有给出确切的链接。
    • 使用这个文件:drive.google.com/open?id=1u5QC5omPLnteWy_luBPZ8l5aXMPB--nA 在那个类中使用你的包名和 R.java 文件。
    【解决方案13】:

    对于 Kotlin:

    只需创建一个名为 URIPathHelper.kt 的新文件。然后将以下实用程序类复制并粘贴到您的文件中。它涵盖了所有场景,适用于所有 Android 版本。它的解释将在后面讨论。

    package com.mvp.handyopinion
    
    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
    
    class URIPathHelper {
    
        fun getPath(context: Context, uri: Uri): String? {
            val isKitKatorAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
    
            // DocumentProvider
            if (isKitKatorAbove && DocumentsContract.isDocumentUri(context, uri)) {
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":".toRegex()).toTypedArray()
                    val type = split[0]
                    if ("primary".equals(type, ignoreCase = true)) {
                        return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                    }
    
                } else if (isDownloadsDocument(uri)) {
                    val id = DocumentsContract.getDocumentId(uri)
                    val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
                    return getDataColumn(context, contentUri, null, null)
                } else if (isMediaDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":".toRegex()).toTypedArray()
                    val type = split[0]
                    var contentUri: Uri? = null
                    if ("image" == type) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    } else if ("video" == type) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    } else if ("audio" == type) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    }
                    val selection = "_id=?"
                    val selectionArgs = arrayOf(split[1])
                    return getDataColumn(context, contentUri, selection, selectionArgs)
                }
            } else if ("content".equals(uri.scheme, ignoreCase = true)) {
                return getDataColumn(context, uri, null, null)
            } else if ("file".equals(uri.scheme, ignoreCase = true)) {
                return uri.path
            }
            return null
        }
    
        fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
            var cursor: Cursor? = null
            val column = "_data"
            val projection = arrayOf(column)
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,null)
                if (cursor != null && cursor.moveToFirst()) {
                    val column_index: Int = cursor.getColumnIndexOrThrow(column)
                    return cursor.getString(column_index)
                }
            } finally {
                if (cursor != null) cursor.close()
            }
            return null
        }
    
        fun isExternalStorageDocument(uri: Uri): Boolean {
            return "com.android.externalstorage.documents" == uri.authority
        }
    
        fun isDownloadsDocument(uri: Uri): Boolean {
            return "com.android.providers.downloads.documents" == uri.authority
        }
    
        fun isMediaDocument(uri: Uri): Boolean {
            return "com.android.providers.media.documents" == uri.authority
        }
    }
    

    如何使用 URIPathHelper 类从 URI 中获取路径

    val uriPathHelper = URIPathHelper()
    val filePath = uriPathHelper.getPath(this, YOUR_URI_OBJECT)
    

    【讨论】:

    • 引起:java.lang.IllegalArgumentException:列'_data'不存在。可用列:[] 我在尝试添加音频文件时遇到此错误
    • Environment.getExternalStorageDirectory() 已弃用
    【解决方案14】:

    唯一的问题是获取下载目录的路径或msf和NumberFormat异常,试试这个。它对我很有效

        package com.example.bookingmelbourne;
        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.provider.OpenableColumns;
        import android.text.TextUtils;
        import android.util.Log;
        
        import androidx.annotation.Nullable;
        import androidx.annotation.WorkerThread;
        
        import java.io.File;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.OutputStream;
        
        public class FileUtils {
            private static final String TAG = "FileUtils";
        @WorkerThread
        @Nullable
        public static String getReadablePathFromUri(Context context, Uri uri) {
    
            String path = null;
            if ("file".equalsIgnoreCase(uri.getScheme())) {
                path = uri.getPath();
            }
    
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
                path = getPath(context, uri);
            }
    
            if (TextUtils.isEmpty(path)) {
                return path;
            }
    
            Log.d(TAG, "get path from uri: " + path);
            if (!isReadablePath(path)) {
                int index = path.lastIndexOf("/");
                String name = path.substring(index + 1);
                String dstPath = context.getCacheDir().getAbsolutePath() + File.separator + name;
                if (copyFile(context, uri, dstPath)) {
                    path = dstPath;
                    Log.d(TAG, "copy file success: " + path);
                } else {
                    Log.d(TAG, "copy file fail!");
                } 
            }
            return path;
        }
    
        public static String getPath(final Context context, final Uri uri) {
            final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    Log.d("External Storage", docId);
                    final String[] split = docId.split(":");
                    final String type = split[0];
    
                    if ("primary".equalsIgnoreCase(type)) {
                        return Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                } else if (isDownloadsDocument(uri)) {
    
                    String dstPath = context.getCacheDir().getAbsolutePath() + File.separator + getFileName(context,uri);
    
                     if (copyFile(context, uri, dstPath)) {
                        Log.d(TAG, "copy file success: " + dstPath);
                        return dstPath;
    
                    } else {
                        Log.d(TAG, "copy file fail!");
                    }
    
    
                } else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final 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;
                    }
    
                    final String selection = "_id=?";
                    final 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 static String getFileName(Context context, Uri uri) {
    
            Cursor cursor = context.getContentResolver().query(uri,null,null,null,null);
            int nameindex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            cursor.moveToFirst();
    
            return  cursor.getString(nameindex);
        }
    
    
        private static 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;
        }
    
        private static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        private static boolean isReadablePath(@Nullable String path) {
            if (TextUtils.isEmpty(path)) {
                return false;
            }
            boolean isLocalPath;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                if (!TextUtils.isEmpty(path)) {
                    File localFile = new File(path);
                    isLocalPath = localFile.exists() && localFile.canRead();
                } else {
                    isLocalPath = false;
                }
            } else {
                isLocalPath = path.startsWith(File.separator);
            }
            return isLocalPath;
        }
    
        private static boolean copyFile(Context context, Uri uri, String dstPath) {
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                inputStream = context.getContentResolver().openInputStream(uri);
                outputStream = new FileOutputStream(dstPath);
    
                byte[] buff = new byte[100 * 1024];
                int len;
                while ((len = inputStream.read(buff)) != -1) {
                    outputStream.write(buff, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return true;
        }
    
      }
    

    之后,你可以调用这个方法传递上下文和uri对象

    FileUtils.getReadablePathFromUri(context,uri)
    

    【讨论】:

    • 非常感谢这个解决方案,它运行良好,我使用了这个代码。
    • 它没有显示正确的路径
    【解决方案15】:

    由于这里的大多数解决方案都不适用于不推荐使用 Environment.getExternalStorageDirectory() 的 API 30+,或者解析作为系统内部信息的文档 id,因此值得一问:您真的需要 em> 路径?

    如果您只是需要一种访问项目数据的方法,那么在所有平台上都有一种直接的方法:

    fun getInputStream(context: Context, uri: Uri): InputStream? {
        return context.contentResolver.openInputStream(uri)
    }
    

    如果需要显示名(如test.jpg),也可以使用内容解析器:

    fun getDisplayName(context: Context, uri: Uri): String? {
        context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)
            .use {
                if (it == null || !it.moveToFirst()) {
                    return null
                }
    
                val columnIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                if (columnIndex == -1) {
                    return null
                }
    
                return it.getString(columnIndex)
            }
    }
    
    

    只是想我会提到它,因为它会对我有所帮助。

    【讨论】:

      【解决方案16】:

      我们都同意 SAF 的设计非常糟糕且缓慢,但 Google 一直在推动我们这样做。鉴于getExternalStorageDirectory() 早已被弃用,并且可能从 11 年起可能无法使用,我宁愿不使用这些解决方案,因为它距离崩溃只有一次更新......

      【讨论】:

      • 那么您的建议答案是什么?你应该提供一个可靠的答案和解决方案我不是吗?你在这里表达你的意见“作为一个答案”
      • @elliotching 同意,然后给我投反对票。我很沮丧(因为人们仍在努力更新代码),情绪激动(我遇到了同样的问题,并且无法接受一个骇人听闻的解决方案),然后输入了这个。在我的辩护中,答案是骇人听闻的,不可靠的,不可测试的。为什么我不编辑答案:太多了,所以要求答案不会被彻底改变。为什么我没有评论:太多了。
      【解决方案17】:

      我更喜欢使用Simple Storage

      // For document file
      val documentFile = DocumentFileCompat.fromUri(context, uri)
      val path = documentFile.absolutePath // e.g. /storage/emulated/0/Music/Torisetsu.mp3
      
      // For media file
      val mediaFile = MediaFile(context, uri)
      val path = mediaFile.absolutePath // e.g. /storage/emulated/0/Music/My Love.mp3
      

      要检查URI是媒体文件还是文档文件,使用isMediaDocument扩展函数:

      val isMediaFile = uri.isMediaDocument
      

      【讨论】:

        【解决方案18】:

        这节省了我的时间。从 URI 获取路径的最简单方法。

          //kotlin
          myuri = data.data
          val realPath = myuri.path
          Log.d(TAG, "path: $realPath")
        

        返回路径:

         path: /storage/emulated/0/Download/CutOFF - Escuro (Original Mix).mp3
        

        【讨论】:

        • 某些设备返回“content://...”作为您的 realPath,它根本无法正常工作
        【解决方案19】:

        适用于所有 api 版本(在 Android 10 上测试)

        val returnCursor: Cursor? = context.contentResolver.query(uri, null, null, null, null)
                    val columnIndex = returnCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    returnCursor.moveToFirst();
                    val path = returnCursor.getString(columnIndex)
        

        【讨论】:

          【解决方案20】:

          如果您有权访问文件并希望避免使用ContentResolver 或直接读取文件,请参阅答案:https://stackoverflow.com/a/67499473/6367262

          【讨论】:

            【解决方案21】:

            如果你的目标是 android 11 (api level 30) 或更高版本,即使你从 uri 中获取文件路径,你也无法访问该文件,你会发现 FileNotFoundException (permission denied)

            因为从 android 11 开始,应用程序只允许从自己的应用程序特定目录(例如:Android/data/packagename)访问文件。

            不过有个权限叫

            MANAGE_EXTERNAL_STORAGE

            允许应用访问所有存储文件。但是,如果您想将您的应用发布到 Play 商店,根据商店政策,此权限不适用于所有类型的应用。检查这个link

            那么解决办法是什么?

            您可以从 URI 获取输入流并使用它,如果它适合您的用例(例如通过改造上传文件,转换为位图等)

            如果您迫切需要 File 对象,那么您必须将输入流转换为文件并将其存储在您的应用程序特定目录中。

            object FileUtils {
            
            val cRes = BaseApplication.instance.contentResolver
            
            
            
            @Throws(IOException::class)
            fun getInputStream(uri:Uri): InputStream? {
                return if (isVirtualFile(uri)){
                    getInputStreamForVirtualFile(uri, getMimeType(uri))
                }else{
                    cRes.openInputStream(uri)
                }
            }
            
            fun getMimeType(uri: Uri): String? {
                return cRes.getType(uri)
            }
            
            private fun isVirtualFile(uri: Uri): Boolean {
            
                if (!DocumentsContract.isDocumentUri(BaseApplication.instance, uri)) {
                    return false
                }
            
                val cursor: Cursor? = cRes.query(
                    uri,
                    arrayOf(DocumentsContract.Document.COLUMN_FLAGS),
                    null,
                    null,
                    null
                )
            
                val flags: Int = cursor?.use {
                    if (cursor.moveToFirst()) {
                        cursor.getInt(0)
                    } else {
                        0
                    }
                } ?: 0
            
                return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    flags and DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT != 0
                } else {
                    return false
                }
            }
            
            @Throws(IOException::class)
            private fun getInputStreamForVirtualFile(
                uri: Uri, mimeTypeFilter: String?): FileInputStream? {
            
                if (mimeTypeFilter==null){
                    throw FileNotFoundException()
                }
                val openableMimeTypes: Array<String>? =
                    cRes.getStreamTypes(uri, mimeTypeFilter)
            
                return if (openableMimeTypes?.isNotEmpty() == true) {
                    cRes
                        .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)?.createInputStream()
                } else {
                    throw FileNotFoundException()
                }
            }
            
            fun copyStreamToFile(inputStream: InputStream, outputFile: File) {
                inputStream.use { input ->
                    val outputStream = FileOutputStream(outputFile)
                    outputStream.use { output ->
                        val buffer = ByteArray(4 * 1024) // buffer size
                        while (true) {
                            val byteCount = input.read(buffer)
                            if (byteCount < 0) break
                            output.write(buffer, 0, byteCount)
                        }
                        output.flush()
                    }
                }
            }
            

            }

            打开文件选择器时使用这个

                  Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            

            没有

                  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            

            【讨论】:

              【解决方案22】:

              @S.A.Parkhid 在 kotlin 上的回答。

              class FileUtils @Inject constructor(private val context: Context) {
              
                  private var selection: String? = null
                  private var selectionArgs: Array<String>? = null
              
                  fun getFile(uri: Uri): File? {
                      val path = getPath(uri)
                      return if (path != null) {
                          File(path)
                      } else {
                          null
                      }
                  }
              
                  fun getPath(uri: Uri): String? {
                      // check here to KITKAT or new version
                      return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                          getPathForKitKatAndAbove(uri)
                      } else {
                          getPathBelowKitKat(uri)
                      }
                  }
              
                  @SuppressLint("NewApi")
                  private fun handleExternalStorage(uri: Uri): String? {
                      val docId = DocumentsContract.getDocumentId(uri)
                      val split = docId.split(":".toRegex()).toTypedArray()
                      val fullPath = getPathFromExtSD(split)
                      return if (fullPath !== "") {
                          fullPath
                      } else {
                          null
                      }
                  }
              
                  @SuppressLint("NewApi")
                  private fun handleDownloads(uri: Uri): String? {
                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                          handleDownloads23ApiAndAbove(uri)
                      } else {
                          handleDownloadsBelow23Api(uri)
                      }
                      return null
                  }
              
                  @SuppressLint("NewApi")
                  private fun handleDownloadsBelow23Api(uri: Uri): String? {
                      val id = DocumentsContract.getDocumentId(uri)
                      if (id.startsWith("raw:")) {
                          return id.replaceFirst("raw:".toRegex(), "")
                      }
                      var contentUri: Uri? = null
                      try {
                          contentUri = ContentUris.withAppendedId(
                              Uri.parse("content://downloads/public_downloads"), id.toLong()
                          )
                      } catch (e: NumberFormatException) {
                          log(e)
                      }
                      if (contentUri != null) {
                          return getDataColumn(contentUri)
                      }
                      return null
                  }
              
                  @SuppressLint("NewApi")
                  private fun handleDownloads23ApiAndAbove(uri: Uri): String? {
                      var cursor: Cursor? = null
                      try {
                          cursor = context.contentResolver
                              .query(uri, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null)
                          if (cursor != null && cursor.moveToFirst()) {
                              val fileName = cursor.getString(0)
                              val path: String =
                                  Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
                              if (path.isNotEmpty()) {
                                  return path
                              }
                          }
                      } finally {
                          cursor?.close()
                      }
                      val id: String = DocumentsContract.getDocumentId(uri)
                      if (id.isNotEmpty()) {
                          if (id.startsWith("raw:")) {
                              return id.replaceFirst("raw:".toRegex(), "")
                          }
                          val contentUriPrefixesToTry = arrayOf(
                              "content://downloads/public_downloads",
                              "content://downloads/my_downloads"
                          )
                          for (contentUriPrefix in contentUriPrefixesToTry) {
                              return try {
                                  val contentUri = ContentUris.withAppendedId(
                                      Uri.parse(contentUriPrefix),
                                      id.toLong()
                                  )
                                  getDataColumn(contentUri)
                              } catch (e: NumberFormatException) {
                                  //In Android 8 and Android P the id is not a number
                                  uri.path.orEmpty().replaceFirst("^/document/raw:".toRegex(), "")
                                      .replaceFirst("^raw:".toRegex(), "")
                              }
                          }
                      }
                      return null
                  }
              
                  @SuppressLint("NewApi")
                  private fun handleMedia(uri: Uri): String? {
                      val docId = DocumentsContract.getDocumentId(uri)
                      val split = docId.split(":".toRegex()).toTypedArray()
                      val contentUri: Uri? = when (split[0]) {
                          "image" -> {
                              MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                          }
                          "video" -> {
                              MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                          }
                          "audio" -> {
                              MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                          }
                          else -> null
                      }
                      selection = "_id=?"
                      selectionArgs = arrayOf(split[1])
                      return if (contentUri != null) {
                          getDataColumn(contentUri)
                      } else {
                          null
                      }
                  }
              
                  private fun handleContentScheme(uri: Uri): String? {
                      if (isGooglePhotosUri(uri)) {
                          return uri.lastPathSegment
                      }
                      if (isGoogleDriveUri(uri)) {
                          return getDriveFilePath(uri)
                      }
                      return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                          copyFileToInternalStorage(uri, "userfiles")
                      } else {
                          getDataColumn(uri)
                      }
                  }
              
                  @SuppressLint("NewApi")
                  private fun getPathForKitKatAndAbove(uri: Uri): String? {
                      return when {
                          // ExternalStorageProvider
                          isExternalStorageDocument(uri) -> handleExternalStorage(uri)
                          // DownloadsProvider
                          isDownloadsDocument(uri) -> handleDownloads(uri)
                          // MediaProvider
                          isMediaDocument(uri) -> handleMedia(uri)
                          //GoogleDriveProvider
                          isGoogleDriveUri(uri) -> getDriveFilePath(uri)
                          //WhatsAppProvider
                          isWhatsAppFile(uri) -> getFilePathForWhatsApp(uri)
                          //ContentScheme
                          "content".equals(uri.scheme, ignoreCase = true) -> handleContentScheme(uri)
                          //FileScheme
                          "file".equals(uri.scheme, ignoreCase = true) -> uri.path
                          else -> null
                      }
                  }
              
                  private fun getPathBelowKitKat(uri: Uri): String? {
                      if (isWhatsAppFile(uri)) {
                          return getFilePathForWhatsApp(uri)
                      }
                      if ("content".equals(uri.scheme, ignoreCase = true)) {
                          val projection = arrayOf(
                              MediaStore.Images.Media.DATA
                          )
                          var cursor: Cursor? = null
                          try {
                              cursor = context.contentResolver
                                  .query(uri, projection, selection, selectionArgs, null)
                              val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
                              if (cursor.moveToFirst()) {
                                  return cursor.getString(columnIndex)
                              }
                          } catch (e: IOException) {
                              log(e)
                          } finally {
                              cursor?.close()
                          }
                      }
                      return null
                  }
              
                  private fun fileExists(filePath: String): Boolean {
                      val file = File(filePath)
                      return file.exists()
                  }
              
                  private fun getPathFromExtSD(pathData: Array<String>): String {
                      val type = pathData[0]
                      val relativePath = "/" + pathData[1]
                      var fullPath: String
              
                      // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
                      // something like "71F8-2C0A", some kind of unique id per storage
                      // don't know any API that can get the root path of that storage based on its id.
                      //
                      // so no "primary" type, but let the check here for other devices
                      if ("primary".equals(type, ignoreCase = true)) {
                          fullPath = Environment.getExternalStorageDirectory().toString() + relativePath
                          if (fileExists(fullPath)) {
                              return fullPath
                          }
                      }
              
                      // Environment.isExternalStorageRemovable() is `true` for external and internal storage
                      // so we cannot relay on it.
                      //
                      // instead, for each possible path, check if file exists
                      // we'll start with secondary storage as this could be our (physically) removable sd card
                      fullPath = System.getenv("SECONDARY_STORAGE").orEmpty() + relativePath
                      if (fileExists(fullPath)) {
                          return fullPath
                      }
                      fullPath = System.getenv("EXTERNAL_STORAGE").orEmpty() + relativePath
                      return if (fileExists(fullPath)) {
                          fullPath
                      } else fullPath
                  }
              
                  private fun getDriveFilePath(uri: Uri): String? {
                      context.contentResolver.query(
                          uri, null, null, null, null
                      )?.use { cursor ->
                          /*
                           * Get the column indexes of the data in the Cursor,
                           *     * move to the first row in the Cursor, get the data,
                           *     * and display it.
                           * */
                          val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                          cursor.moveToFirst()
                          val name = cursor.getString(nameIndex)
                          val file = File(context.cacheDir, name)
                          try {
                              val inputStream = context.contentResolver.openInputStream(uri)!!
                              val outputStream = FileOutputStream(file)
                              val bytesAvailable = inputStream.available()
              
                              val bufferSize = min(bytesAvailable, MAX_BUFFER_SIZE)
                              val buffers = ByteArray(bufferSize)
                              var read: Int
                              while (inputStream.read(buffers).also { read = it } != -1) {
                                  outputStream.write(buffers, 0, read)
                              }
                              inputStream.close()
                              outputStream.close()
                          } catch (e: IOException) {
                              log(e)
                          } finally {
                              cursor.close()
                          }
                          return file.path
                      }
                      return null
                  }
              
                  /***
                   * Used for Android Q+
                   * @param uri
                   * @param newDirName if you want to create a directory, you can set this variable
                   * @return
                   */
                  private fun copyFileToInternalStorage(uri: Uri, newDirName: String): String? {
                      context.contentResolver.query(
                          uri, arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE), null, null, null
                      )?.use { cursor ->
                          /*
                           * Get the column indexes of the data in the Cursor,
                           *     * move to the first row in the Cursor, get the data,
                           *     * and display it.
                           * */
                          val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                          cursor.moveToFirst()
                          val name = cursor.getString(nameIndex)
                          val output: File = if (newDirName != "") {
                              val dir = File(context.filesDir.toString() + "/" + newDirName)
                              if (!dir.exists()) {
                                  dir.mkdir()
                              }
                              File(context.filesDir.toString() + "/" + newDirName + "/" + name)
                          } else {
                              File(context.filesDir.toString() + "/" + name)
                          }
                          try {
                              val inputStream = context.contentResolver.openInputStream(uri) ?: return null
                              val outputStream = FileOutputStream(output)
                              var read: Int
                              val buffers = ByteArray(BUFFER_SIZE)
                              while (inputStream.read(buffers).also { read = it } != -1) {
                                  outputStream.write(buffers, 0, read)
                              }
                              inputStream.close()
                              outputStream.close()
                          } catch (e: IOException) {
                              log(e)
                          } finally {
                              cursor.close()
                          }
                          return output.path
                      }
                      return null
                  }
              
                  private fun getFilePathForWhatsApp(uri: Uri): String? {
                      return copyFileToInternalStorage(uri, "whatsapp")
                  }
              
                  private fun getDataColumn(uri: Uri): String? {
                      var cursor: Cursor? = null
                      val column = "_data"
                      val projection = arrayOf(column)
                      try {
                          cursor = context.contentResolver.query(
                              uri, projection,
                              selection, selectionArgs, null
                          )
                          if (cursor != null && cursor.moveToFirst()) {
                              val index = cursor.getColumnIndexOrThrow(column)
                              return cursor.getString(index)
                          }
                      } finally {
                          cursor?.close()
                      }
                      return null
                  }
              
                  private fun isExternalStorageDocument(uri: Uri): Boolean {
                      return EXTERNAL_STORAGE_CONTENT == uri.authority
                  }
              
                  private fun isDownloadsDocument(uri: Uri): Boolean {
                      return DOWNLOAD_DOCUMENT_CONTENT == uri.authority
                  }
              
                  private fun isMediaDocument(uri: Uri): Boolean {
                      return MEDIA_DOCUMENT_CONTENT == uri.authority
                  }
              
                  private fun isGooglePhotosUri(uri: Uri): Boolean {
                      return GOOGLE_PHOTOS_CONTENT == uri.authority
                  }
              
                  private fun isWhatsAppFile(uri: Uri): Boolean {
                      return WHATS_APP_CONTENT == uri.authority
                  }
              
                  private fun isGoogleDriveUri(uri: Uri): Boolean {
                      return GOOGLE_DRIVE_CONTENT == uri.authority || "com.google.android.apps.docs.storage.legacy" == uri.authority
                  }
              
                  companion object {
                      private const val BUFFER_SIZE = 1024
                      private const val MAX_BUFFER_SIZE = 1024 * 1024
                      private const val GOOGLE_DRIVE_CONTENT = "com.google.android.apps.docs.storage"
                      private const val WHATS_APP_CONTENT = "com.whatsapp.provider.media"
                      private const val GOOGLE_PHOTOS_CONTENT = "com.google.android.apps.photos.content"
                      private const val MEDIA_DOCUMENT_CONTENT = "com.android.providers.media.documents"
                      private const val DOWNLOAD_DOCUMENT_CONTENT = "com.android.providers.downloads.documents"
                      private const val EXTERNAL_STORAGE_CONTENT = "com.android.externalstorage.documents"
                  }
              }
              

              【讨论】:

                【解决方案23】:

                我很难在 Xamarin 上解决这个问题。根据上面的建议,我想出了这个解决方案。

                private string getRealPathFromURI(Android.Net.Uri contentUri)
                {
                    string filename = "";
                    string thepath = "";
                    Android.Net.Uri filePathUri;
                    ICursor cursor = this.ContentResolver.Query(contentUri, null, null, null, null);
                
                    if (cursor.MoveToFirst())
                    {
                        int column_index = cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
                        filePathUri = Android.Net.Uri.Parse(cursor.GetString(column_index));
                        filename = filePathUri.LastPathSegment;
                        thepath = filePathUri.Path;
                    }
                
                    return thepath;
                }
                

                【讨论】:

                • Android 7.0 Column_Index 在使用ActionContentGet 选择文件时为-1 并键入*/* 让我们说PDF
                【解决方案24】:
                String uri_path = "file:///mnt/sdcard/FileName.mp3";
                File f = new removeUriFromPath(uri_path));
                public static String removeUriFromPath(String uri)
                {
                  return  uri.substring(7, uri.length());
                }
                

                【讨论】:

                • 我的兄弟使用子字符串不是解决方案,因为 uri_path 是动态的!
                • @sanjeev badoni,考虑删除您的答案以恢复您的声誉
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-01-01
                • 1970-01-01
                相关资源
                最近更新 更多