简体   繁体   English

ContentResolver - 如何从 Uri 获取文件名

[英]ContentResolver - how to get file name from Uri

I call startActivityForResult with Intent ACTION_GET_CONTENT .我用Intent ACTION_GET_CONTENT调用startActivityForResult Some app returns me data with this Uri :某些应用程序使用此Uri向我返回数据:

content://media/external/images/media/18122内容://媒体/外部/图像/媒体/18122

I don't know if it is image or video or some custom content.我不知道它是图像还是视频还是一些自定义内容。 How do I use ContentResolver to get the actual file name or content title from this Uri?如何使用ContentResolver从此 Uri 获取实际文件名或内容标题?

@Durairaj's answer is specific to getting the path of a file. @Durairaj 的回答是针对获取文件路径的。 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:如果您要搜索的是文件的实际名称(因为您应该使用内容解析,此时您可能会得到很多 content:// URI),您需要执行以下操作:

(Code copied from Durairaj's answer and modified) (代码从 Durairaj 的回答中复制并修改)

        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.这里要注意的主要部分是我们使用的是MediaStore.MediaColumns.DISPLAY_NAME ,它返回内容的实际名称。 You might also try MediaStore.MediaColumns.TITLE , as I'm not sure what the difference is.您也可以尝试MediaStore.MediaColumns.TITLE ,因为我不确定有什么区别。

You can get file name from this code, or any other field by modifying the projection您可以通过修改投影从此代码或任何其他字段获取文件名

String[] projection = {MediaStore.MediaColumns.DATA};

ContentResolver cr = getApplicationContext().getContentResolver();
Cursor metaCursor = cr.query(uri, projection, null, null, null);
if (metaCursor != null) {
    try {
        if (metaCursor.moveToFirst()) {
            path = metaCursor.getString(0);
        }
    } finally {
        metaCursor.close();
    }
}
return path;

To get filename, you can use new DocumentFile format.要获取文件名,您可以使用新的DocumentFile格式。

DocumentFile documentFile = DocumentFile.fromSingleUri(this, data.getdata());
String fileName = documentFile.getName();

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.对于使用 Kotlin 的任何人遇到同样的问题,您可以定义一个扩展方法来一次性获取文件名和大小(以字节为单位)。 If it is unable to retrieve the fields, it returns null.如果无法检索字段,则返回 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).可能会引发异常,但它从未对我这样做过(只要 URI 是有效的content:// URI)。

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

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:这是我在阅读了此处提供的所有答案以及一些 Airgram 在其 SDK 中所做的工作后得出的结论——我在 Github 上开源的一个实用程序:

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

Usage用法

As simple as calling, UriUtils.getDisplayNameSize() .就像调用UriUtils.getDisplayNameSize()一样简单。 It provides both the name and size of the content.它提供内容的名称和大小。

Note: Only works with a content:// Uri注意:仅适用于 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;
    }
}

You can use the solution proposed by Durairaj with the following as the projection array:您可以将 Durairaj 提出的解决方案与以下投影数组一起使用:

String[] projection = { "_data" };

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

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