简体   繁体   中英

android: Get real path from uri

I want to sen file to server and I need to get real path from uri.

My code:

public String getPathFromURI(Context context, Uri contentUri) {
    if ( contentUri.toString().indexOf("file:///") > -1 ){
        return contentUri.getPath();
    }

    Cursor cursor = null;
    try { 
        String[] proj = { MediaStore.Images.Media.DATA };
        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);
    }finally {
          if (cursor != null) {
              cursor.close();
          }
    }
}

And onActivityResult:

...
imageName = data.getData();
imagePath = getPathFromURI(getBaseContext(),imageName);

Picasso.with(getBaseContext()).load(imageName).into(imageView);
...

How it's possible that image shows in ImageView , but imagePath is ALWAYS null ? :) Thanks

EDIT:

How i send image to server

HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost([URL TO A SERVER]);

MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("uploaded_file_1", new FileBody(new File( imagePath )));

httpPost.setEntity(entity);
httpClient.execute(httpPost, localContext);

I went through some answers on stack, and found the solution...

public static String getPathFromURI(final Context context, final Uri uri) {

    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];
            }
        }
        // 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 getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

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()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

This will find the real path in every case even for kitkat (that was the problem... kitkat)

From android 10 you must use app-specific storage for your files. In case you want file from external storage and do something to it like you want to upload it to the server, you need to get the file and make a copy of it to the app-specific storage.

Here is what you can use, assuming you already have the uri of the selected file.

val parcelFileDescriptor =
    contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?: return

val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)

And the function to get the file name from the Uri is

fun ContentResolver.getFileName(fileUri: Uri): String {
    var name = ""
    val returnCursor = this.query(fileUri, null, null, null, null)
    if (returnCursor != null) {
        val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
        returnCursor.moveToFirst()
        name = returnCursor.getString(nameIndex)
        returnCursor.close()
    }
    return name
}

Now you can use file.path and it will work. If you don't want to do like this then for android 10 there is also a temporary solution that is

android:requestLegacyExternalStorage="true"

You can add this to your AndroidManifest.xml inside application tag.

Reference: Android Upload File to Server

Hope this will help, Thank You :)

here is my simple code ... it'll work 100% and for Android Version > 23

and if you got error while pick image from gallery its recommended

public String getPathFromUri(Uri uri, Activity activity) {
    String[] projection = {MediaStore.MediaColumns.DATA};
    Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}

I couldn't get the path for a Marshmallow phone sharing media from Google Photos to my app. I'll try to explain myself why this is probably happening.

I didn't find any official documentation to base my thought, but I'll share them with you to see if with some collaboration from different minds we reach to a solution.

My theory is that Google Photos does not have the media files physically in the phone, they are probably thumbnails or online. So when you share some pics, they are downloaded temporary and probably stored in the Internal Storage of the App so you can't access it (to the path).

The only workaround I found to get the path of the file is copying it to my app internal storage. I don't like it but everything I tried didn't work for me.

Thanks Michal Heneš and Sam .

After a lot of searching I got solution in java.

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.util.Log;
import android.widget.Switch;

import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;

import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.internal.Intrinsics;
import kotlin.text.Regex;
import kotlin.text.StringsKt;

public class UtilsFile {


    private final static String PUBLIC_DOWNLOAD_PATH = "content://downloads/public_downloads";


    private final static String EXTERNAL_STORAGE_DOCUMENTS_PATH = "com.android.externalstorage.documents";


    private final static String DOWNLOAD_DOCUMENTS_PATH = "com.android.providers.downloads.documents";


    private final static String MEDIA_DOCUMENTS_PATH = "com.android.providers.media.documents";


    private final static String PHOTO_CONTENTS_PATH = "com.google.android.apps.photos.content";


    private Boolean isExternalStorageDocument(Uri uri) {
        return EXTERNAL_STORAGE_DOCUMENTS_PATH.equals(uri.getAuthority());

    }
 private Boolean isPublicDocument(Uri uri) {
        return PUBLIC_DOWNLOAD_PATH.equals(uri.getAuthority());

    }


    private Boolean isDownloadsDocument(Uri uri) {
        return DOWNLOAD_DOCUMENTS_PATH.equals(uri.getAuthority());

    }

    private Boolean isMediaDocument(Uri uri) {
        return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());
    }


    private Boolean isGooglePhotosUri(Uri uri) {
        return MEDIA_DOCUMENTS_PATH.equals(uri.getAuthority());

    }
 private Boolean isPhotoContentUri(Uri uri) {
        return PHOTO_CONTENTS_PATH.equals(uri.getAuthority());

    }



    private String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

        Cursor cursor = null;
        //String column = "_data" REMOVED IN FAVOR OF NULL FOR ALL
        //String projection = arrayOf(column) REMOVED IN FAVOR OF PROJECTION FOR ALL
        try {
            cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
                return cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            Log.e("PathUtils", "Error getting uri for cursor to read file: " + e.getMessage());
        } finally {
            assert cursor != null;
            cursor.close();
        }
        return null;

    }

    public  String getFullPathFromContentUri(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        String filePath="";
        // 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];
                }//non-primary e.g sd card
                else {
                    if (Build.VERSION.SDK_INT > 20) {
                        //getExternalMediaDirs() added in API 21
                        File[] extenal = context.getExternalMediaDirs();
                        for (File f : extenal) {
                            filePath = f.getAbsolutePath();
                            if (filePath.contains(type)) {
                                int endIndex = filePath.indexOf("Android");
                                filePath = filePath.substring(0, endIndex) + split[1];
                            }
                        }
                    }else{
                        filePath = "/storage/" + type + "/" + split[1];
                    }
                    return filePath;
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                String fileName = getDataColumn(context,  uri,null, null);
                String uriToReturn = null;
                if (fileName != null) {
                    uriToReturn = Uri.withAppendedPath(
                            Uri.parse(
                                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()), fileName
                    ).toString();
                }
                return uriToReturn;
            }
            // 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]
                };

                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;
            }

        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        else if (isPublicDocument(uri)){
            String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse(PUBLIC_DOWNLOAD_PATH), Long.parseLong(id));
            String[] projection = {MediaStore.Images.Media.DATA};
            @SuppressLint("Recycle") Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);

            if (cursor != null && cursor.moveToFirst()) {
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            }
        }

        return null;
    }

}

Accessing public download files onActivityResult Android 28 Samsung Galaxy S9+ (Verizon)

you can use this funtion for get file from uri in new android and older

fun getFileFromUri(context: Context, uri: Uri?): File? {
    uri ?: return null
    uri.path ?: return null

    var newUriString = uri.toString()
    newUriString = newUriString.replace(
        "content://com.android.providers.downloads.documents/",
        "content://com.android.providers.media.documents/"
    )
    newUriString = newUriString.replace(
        "/msf%3A", "/image%3A"
    )
    val newUri = Uri.parse(newUriString)

    var realPath = String()
    val databaseUri: Uri
    val selection: String?
    val selectionArgs: Array<String>?
    if (newUri.path?.contains("/document/image:") == true) {
        databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        selection = "_id=?"
        selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1])
    } else {
        databaseUri = newUri
        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 = realPath.ifEmpty {
        when {
            newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace(
                "/document/raw:",
                ""
            )
            newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace(
                "/document/primary:",
                "/storage/emulated/0/"
            )
            else -> return null
        }
    }
    return if (path.isNullOrEmpty()) null else File(path)
}

This code work for me in android 11 and 12

 private static String getRealPathFromURI(Uri uri, Context context) {
                Uri returnUri = uri;
                Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
                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();
            }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM