ContentResolver - 如何从Uri获取文件名

时间:2012-11-07 17:31:08

标签: android android-contentresolver

我使用startActivityForResult Intent致电ACTION_GET_CONTENT。有些应用会使用此Uri返回数据:

内容://媒体/外部/图像/媒体/ 18122

我不知道它是图片,视频还是某些自定义内容。如何使用ContentResolver从此Uri获取实际文件名或内容标题?

7 个答案:

答案 0 :(得分:14)

您可以通过修改投影

从此代码或任何其他字段获取文件名
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;

答案 1 :(得分:14)

@ Durairaj的答案特定于获取文件的路径。如果你要搜索的是文件的实际名称(因为你应该使用内容解析,那么你可能会得到很多内容:// URIs)你'我需要做以下事情:

(从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,因为我不确定区别是什么。

答案 2 :(得分:5)

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

import { Component, Directive, Renderer2, ElementRef } from '@angular/core';

@Directive({
  selector: '[scroller-directive]',
})
export class ScrollerDirective {
  constructor(elRef: ElementRef, renderer: Renderer2) {
    renderer.listen(elRef.nativeElement, 'wheel', (event) => {
      const el = elRef.nativeElement;
      const conditions = ((el.scrollTop + el.offsetHeight >= el.scrollHeight)) && event.deltaY > 0 || el.scrollTop === 0 && event.deltaY < 0;
      if (conditions === true) {
        event.preventDefault();
        event.returnValue = false;
      }
    });
  }
}

答案 3 :(得分:0)

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

答案 4 :(得分:0)

对于使用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 :(得分:0)

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

在阅读完此处给出的所有答案以及一些Airgram在其SDK中所做的工作后,我得出的结论是-我在Github上开源了该实用程序:

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

用法

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

注意:仅适用于内容:// 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;
    }
}

答案 6 :(得分:-2)

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

String[] projection = { "_data" };