【问题标题】:ContentResolver - how to get file name from UriContentResolver - 如何从 Uri 获取文件名
【发布时间】:2012-10-27 19:42:24
【问题描述】:

我打电话给startActivityForResultIntent ACTION_GET_CONTENT。一些应用程序通过此Uri 向我返回数据:

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

我不知道是图片还是视频还是一些自定义内容。如何使用ContentResolver 从这个 Uri 中获取实际的文件名或内容标题?

【问题讨论】:

  • 请注意,可能没有文件。内容可能来自 Google Drive,也可能来自其他动态生成内容的来源。也许你想改用getContentResolver().openInputStream(uri)
  • 当然可以。该名称仅用于显示目的。

标签: android android-contentresolver


【解决方案1】:

@Durairaj 的答案是特定于获取文件的 path。如果您要搜索的是文件的实际名称(因为您应该使用内容解析,此时您可能会得到很多 content:// URI),您需要执行以下操作:

(从 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();
            }
        }

这里要注意的主要部分是我们使用MediaStore.MediaColumns.DISPLAY_NAME,它返回内容的实际名称。你也可以试试MediaStore.MediaColumns.TITLE,因为我不确定有什么区别。

【讨论】:

  • 我猜MediaStore.MediaColumns.DISPLAY_NAME 只对content://media/ uris 有效。
  • @EdwardFalk 这不是真的,该常量只是OpenableColumns.DISPLAY_NAME 的内联别名,在Retrieving File Information 中有详细记录,合理的ContentProviders 应该处理该列:“提供查询时提供可打开的 URI 必须至少支持这些列。"来自OpenableColumns
  • 好点。什么构成“可打开”的 Uri?是否包含“file://”?
【解决方案2】:

您可以从此代码中获取文件名,或通过修改投影来获取任何其他字段

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;

【讨论】:

  • 如果我不知道投影?例如在我的应用中获得可以保存任何文件的意图
  • @Durairaj P:这对我不起作用。如果我单击文件管理器中的文件,它会起作用,但如果我单击电子邮件中的附件,我仍然会得到content://... 字符串。有什么线索吗?
  • @LuisA.Florit 您可能不再有这个问题,但我在获取文件名而不是路径的问题上发布了一个新答案。 stackoverflow.com/a/23270545/43790
【解决方案3】:

要获取文件名,可以使用新的DocumentFile 格式。

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

【讨论】:

  • 工作就像一个魅力。谢谢!
【解决方案4】:

对于任何使用 Kotlin 且有同样问题的人,您可以定义一个扩展方法来一举获取文件名和大小(以字节为单位)。如果无法检索到字段,则返回 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)
    }
}

这样使用它

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

可能抛出异常,但对我来说从来没有这样做过(只要 URI 是有效的 content:// URI)。

【讨论】:

    【解决方案5】:
    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;
    }
    

    【讨论】:

    • 请在您的回答中添加一些解释。
    • 您可以使用上面的方法代码从uri中获取文件名。如果内容解析器不起作用,则使用 CursorLoader。
    【解决方案6】:

    接受的答案不完整。错过了更多支票。

    这是我在阅读了此处提供的所有答案以及一些 Airgram 在他们的 SDK 中所做的事情后得出的结论 - 我在 Github 上开源的实用程序:

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

    用法

    就像打电话一样简单,UriUtils.getDisplayNameSize()。它提供了内容的名称和大小。

    注意:仅适用于 content:// Uri

    下面是代码的一瞥:

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

    【讨论】:

      【解决方案7】:

      您可以使用 Durairaj 提出的解决方案,并将以下内容作为投影数组:

      String[] projection = { "_data" };
      

      【讨论】:

      • 最好使用常量MediaStore.MediaColumns.DATA
      猜你喜欢
      • 1970-01-01
      • 2011-09-25
      • 2014-07-31
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多