简体   繁体   English

android:从uri获取真实路径

[英]android: Get real path from uri

I want to sen file to server and I need to get real path from uri.我想将文件发送到服务器,我需要从 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:和 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 ?图像如何显示在 ImageView 中,但 imagePath 始终为 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)这将在每种情况下找到真正的路径,即使对于 kitkat (这就是问题...... kitkat)

From android 10 you must use app-specific storage for your files.从 android 10 开始,您必须为文件使用特定于应用程序的存储空间。 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.这是您可以使用的,假设您已经拥有所选文件的 uri。

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从 Uri 获取文件名的函数是

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.现在你可以使用file.path并且它会工作。 If you don't want to do like this then for android 10 there is also a temporary solution that is如果您不想这样做,那么对于 android 10,还有一个临时解决方案是

android:requestLegacyExternalStorage="true"

You can add this to your AndroidManifest.xml inside application tag.您可以将其添加到应用程序标记内的 AndroidManifest.xml 中。

Reference: Android Upload File to Server参考: Android 上传文件到服务器

Hope this will help, Thank You :)希望这会有所帮助,谢谢:)

here is my simple code ... it'll work 100% and for Android Version > 23 这是我的简单代码......它将100%工作,Android版本> 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.我无法将 Marshmallow 手机共享媒体从 Google 照片到我的应用程序的路径。 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 .感谢 Michal Heneš 和 Sam。

After a lot of searching I got solution in java.经过大量搜索,我在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) 访问 ActivityResult 上的公共下载文件 Android 28 Samsung Galaxy S9+ (Verizon)

you can use this funtion for get file from uri in new android and older您可以使用此功能从新 android 和旧版本的 uri 中获取文件

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此代码适用于我在 android 11 和 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();
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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