如何从 URI 获取完整的文件路径

Posted

技术标签:

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

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

【问题讨论】:

【参考方案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()。您需要为此实施解决方法

【讨论】:

我们可以使用 String strPath = FileUtils.getPath(uri)); 访问路径 以上代码的更新版本可以是:***.com/questions/13209494/… 太棒了。让我开心。 在不使用已弃用的 getExternalStorageDirectory()、@Nadeem Iqbal 的情况下,我们是否有相同的更新答案? —— @MdBasha : ***.com/questions/13209494/…【参考方案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);

【讨论】:

代码编辑经常被拒绝。 I noticed one suggesting an alternative function that is not deprecated 这给了我空光标,uri 是这样的 - file:/// @MartinSmith 仍然收到null @AnkitaShah : 你必须尝试以下不同安卓版本的答案【参考方案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 (***.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://***.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,考虑删除您的答案以恢复您的声誉

以上是关于如何从 URI 获取完整的文件路径的主要内容,如果未能解决你的问题,请参考以下文章

使用其完整路径作为URI从隔离存储中访问文件

如何从android pie中的内容uri获取文件路径

如何从 Uri xamarin android 获取实际路径

存储访问框架获取正确的 Uri 路径删除/编辑/获取文件

从android中的文件路径获取内容uri

从完整文件路径获取文件夹名称