ContentResolver - how to get file name from Uri

后端 未结 7 530
误落风尘
误落风尘 2020-12-30 03:38

I call startActivityForResult with Intent ACTION_GET_CONTENT. Some app returns me data with this Uri:

content://media/external/images/media/18122

I

相关标签:
7条回答
  • 2020-12-30 03:44

    @Durairaj's answer is specific to getting the path of a file. If what you're searching for is the file's actual name (since you should be using Content Resolution, at which point you'll probably get a lot of content:// URIs) you'll need to do the following:

    (Code copied from Durairaj's answer and modified)

            String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
            Cursor metaCursor = cr.query(uri, projection, null, null, null);
            if (metaCursor != null) {
                try {
                    if (metaCursor.moveToFirst()) {
                        fileName = metaCursor.getString(0);
                    }
                } finally {
                    metaCursor.close();
                }
            }
    

    The main piece to note here is that we're using MediaStore.MediaColumns.DISPLAY_NAME, which returns the actual name of the content. You might also try MediaStore.MediaColumns.TITLE, as I'm not sure what the difference is.

    0 讨论(0)
  • 2020-12-30 03:49

    For anyone using Kotlin who has the same problem, you can define an extension method to get the file name and size (in bytes) in one fell swoop. If it is unable to retrieve the fields, it returns null.

    fun Uri.contentSchemeNameAndSize(): Pair<String, Int>? {
        return contentResolver.query(this, null, null, null, null)?.use { cursor ->
            if (!cursor.moveToFirst()) return@use null
    
            val name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            val size = cursor.getColumnIndex(OpenableColumns.SIZE)
    
            cursor.getString(name) to cursor.getInt(size)
        }
    }
    

    Use it thusly

    val nameAndSize = yourUri.contentNameAndSize()
    // once you've confirmed that is not null, you can then do
    val (name, size) = nameAndSize
    

    It might throw an exception, but it hasn't ever done so for me (as long as the URI is a valid content:// URI).

    0 讨论(0)
  • 2020-12-30 03:51

    To get filename, you can use new DocumentFile format.

    DocumentFile documentFile = DocumentFile.fromSingleUri(this, data.getdata());
    String fileName = documentFile.getName();
    
    0 讨论(0)
  • 2020-12-30 03:55
    private static String getRealPathFromURI(Context context, Uri contentUri)
    {
        String[] proj = { MediaStore.Images.Media.DATA };
        CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String result = cursor.getString(column_index);
        cursor.close();
        return result;
    }
    
    0 讨论(0)
  • 2020-12-30 03:57

    The accepted answer is not complete. There are more checks missed out.

    Here is what I have arrived at after a read of all the answers presented here as well what some Airgram has done in their SDKs - A utility that I have open sourced on Github:

    https://github.com/mankum93/UriUtilsAndroid/tree/master/app/src/main/java/com/androiduriutils

    Usage

    As simple as calling, UriUtils.getDisplayNameSize(). It provides both the name and size of the content.

    Note: Only works with a content:// Uri

    Here is a glimpse on the code:

    /**
     * References:
     * - https://www.programcreek.com/java-api-examples/?code=MLNO/airgram/airgram-master/TMessagesProj/src/main/java/ir/hamzad/telegram/MediaController.java
     * - https://stackoverflow.com/questions/5568874/how-to-extract-the-file-name-from-uri-returned-from-intent-action-get-content
     *
     * @author Manish@bit.ly/2HjxA0C
     * Created on: 03-07-2020
     */
    public final class UriUtils {
    
    
        public static final int CONTENT_SIZE_INVALID = -1;
    
        /**
         * @param context context
         * @param contentUri content Uri, i.e, of the scheme <code>content://</code>
         * @return The Display name and size for content. In case of non-determination, display name
         * would be null and content size would be {@link #CONTENT_SIZE_INVALID}
         */
        @NonNull
        public static DisplayNameAndSize getDisplayNameSize(@NonNull Context context, @NonNull Uri contentUri){
    
            final String scheme = contentUri.getScheme();
            if(scheme == null || !scheme.equals(ContentResolver.SCHEME_CONTENT)){
                throw new RuntimeException("Only scheme content:// is accepted");
            }
    
            final DisplayNameAndSize displayNameAndSize = new DisplayNameAndSize();
            displayNameAndSize.size = CONTENT_SIZE_INVALID;
    
            String[] projection = new String[]{MediaStore.Images.Media.DATA, OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
            Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
            try {
                if (cursor != null && cursor.moveToFirst()) {
    
                    // Try extracting content size
    
                    int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
                    if (sizeIndex != -1) {
                        displayNameAndSize.size = cursor.getLong(sizeIndex);
                    }
    
                    // Try extracting display name
                    String name = null;
    
                    // Strategy: The column name is NOT guaranteed to be indexed by DISPLAY_NAME
                    // so, we try two methods
                    int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                    if (nameIndex != -1) {
                        name = cursor.getString(nameIndex);
                    }
    
                    if (nameIndex == -1 || name == null) {
                        nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                        if (nameIndex != -1) {
                            name = cursor.getString(nameIndex);
                        }
                    }
                    displayNameAndSize.displayName = name;
                }
            }
            finally {
                if(cursor != null){
                    cursor.close();
                }
            }
    
            // We tried querying the ContentResolver...didn't work out
            // Try extracting the last path segment
            if(displayNameAndSize.displayName == null){
                displayNameAndSize.displayName = contentUri.getLastPathSegment();
            }
    
            return displayNameAndSize;
        }
    }
    
    0 讨论(0)
  • 2020-12-30 04:00

    You can use the solution proposed by Durairaj with the following as the projection array:

    String[] projection = { "_data" };
    
    0 讨论(0)
提交回复
热议问题