Viktor Brešan
Viktor Brešan

Reputation: 5528

How to extract the file name from URI returned from Intent.ACTION_GET_CONTENT?

I am using 3rd party file manager to pick a file (PDF in my case) from the file system.

This is how I launch the activity:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(getString(R.string.app_pdf_mime_type));
intent.addCategory(Intent.CATEGORY_OPENABLE);

String chooserName = getString(R.string.Browse);
Intent chooser = Intent.createChooser(intent, chooserName);

startActivityForResult(chooser, ActivityRequests.BROWSE);

This is what I have in onActivityResult:

Uri uri = data.getData();
if (uri != null) {
    if (uri.toString().startsWith("file:")) {
        fileName = uri.getPath();
    } else { // uri.startsWith("content:")

        Cursor c = getContentResolver().query(uri, null, null, null, null);

        if (c != null && c.moveToFirst()) {

            int id = c.getColumnIndex(Images.Media.DATA);
            if (id != -1) {
                fileName = c.getString(id);
            }
        }
    }
}

Code snippet is borrowed from Open Intents File Manager instructions available here:
http://www.openintents.org/en/node/829

The purpose of if-else is backwards compatibility. I wonder if this is a best way to get the file name as I have found that other file managers return all kind of things.

For example, Documents ToGo return something like the following:

content://com.dataviz.dxtg.documentprovider/document/file%3A%2F%2F%2Fsdcard%2Fdropbox%2FTransfer%2Fconsent.pdf

on which getContentResolver().query() returns null.

To make things more interesting, unnamed file manager (I got this URI from client log) returned something like:

/./sdcard/downloads/.bin


Is there a preferred way of extracting the file name from URI or one should resort to string parsing?

Upvotes: 163

Views: 173156

Answers (24)

HAZEEM JOONUS
HAZEEM JOONUS

Reputation: 573

Try this,

Intent data = result.getData();
// check condition
if (data != null) {
    Uri sUri = data.getData();
    @SuppressLint("Recycle")
    Cursor returnCursor = getContentResolver().query(sUri, null, null, null, null);
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    returnCursor.moveToFirst();
    String file_name = returnCursor.getString(nameIndex);
}
                    

Upvotes: 2

UdaraWanasinghe
UdaraWanasinghe

Reputation: 2852

My answer would be an overkill, but here is how you can get filename from 4 different uri types in android.

  1. Content provider uri [content://com.example.app/sample.png]
  2. File uri [file://data/user/0/com.example.app/cache/sample.png]
  3. Resource uri [android.resource://com.example.app/1234567890] or [android.resource://com.example.app/raw/sample]
  4. Http uri [https://example.com/sample.png]
fun Uri.name(context: Context): String {
    when (scheme) {
        ContentResolver.SCHEME_FILE -> {
            return toFile().nameWithoutExtension
        }
        ContentResolver.SCHEME_CONTENT -> {
            val cursor = context.contentResolver.query(
                this,
                arrayOf(OpenableColumns.DISPLAY_NAME),
                null,
                null,
                null
            ) ?: throw Exception("Failed to obtain cursor from the content resolver")
            cursor.moveToFirst()
            if (cursor.count == 0) {
                throw Exception("The given Uri doesn't represent any file")
            }
            val displayNameColumnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            val displayName = cursor.getString(displayNameColumnIndex)
            cursor.close()
            return displayName.substringBeforeLast(".")
        }
        ContentResolver.SCHEME_ANDROID_RESOURCE -> {
            // for uris like [android.resource://com.example.app/1234567890]
            var resourceId = lastPathSegment?.toIntOrNull()
            if (resourceId != null) {
                return context.resources.getResourceName(resourceId)
            }
            // for uris like [android.resource://com.example.app/raw/sample]
            val packageName = authority
            val resourceType = if (pathSegments.size >= 1) {
                pathSegments[0]
            } else {
                throw Exception("Resource type could not be found")
            }
            val resourceEntryName = if (pathSegments.size >= 2) {
                pathSegments[1]
            } else {
                throw Exception("Resource entry name could not be found")
            }
            resourceId = context.resources.getIdentifier(
                resourceEntryName,
                resourceType,
                packageName
            )
            return context.resources.getResourceName(resourceId)
        }
        else -> {
            // probably a http uri
            return toString().substringBeforeLast(".").substringAfterLast("/")
        }
    }
}

Upvotes: 9

WhiteVulpes
WhiteVulpes

Reputation: 29

How about this?

 Uri uri = result.getData().getClipData().getItemAt(i).getUri();
 uri = Uri.parse(uri.getLastPathSegment());
 System.out.println(uri.getLastPathSegment());

This prints the file name with extension

Upvotes: 2

Zhar
Zhar

Reputation: 3530

Here is my utils method to achieve this. You can copy/paste and use it from anywhere.

public class FileUtils {

    /**
     * Return file name from Uri given.
     * @param context the context, cannot be null.
     * @param uri uri request for file name, cannot be null
     * @return the corresponding display name for file defined in uri or null if error occurs.
     */
    public String getNameFromURI(@NonNull Context context,  @NonNull Uri uri) {
        String result = null;
        Cursor c = null;
        try {
            c = context.getContentResolver().query(uri, null, null, null, null);
            c.moveToFirst();
            result = c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        }
        catch (Exception e){
            // error occurs
        }
        finally {
            if(c != null){
                c.close();
            }
        }
        return result;
    }
...
}

And usage.

String fileName = FileUtils.getNameFromContentUri(context, myuri);
if(fileName != null){
    // do stuff
}

Regards.

Upvotes: 3

OhhhThatVarun
OhhhThatVarun

Reputation: 4321

If anyone is looking for a Kotlin answer especially an extension function, here is the way to go.

fun Uri.getOriginalFileName(context: Context): String? {
    return context.contentResolver.query(this, null, null, null, null)?.use {
        val nameColumnIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
        it.moveToFirst()
        it.getString(nameColumnIndex)
    }
}

Upvotes: 3

Tamim Attafi
Tamim Attafi

Reputation: 2511

For Kotlin you can use something like this:

fun Context.getFileName(uri: Uri): String? = when(uri.scheme) {
    ContentResolver.SCHEME_CONTENT -> getContentFileName(uri)
    else -> uri.path?.let(::File)?.name
}

private fun Context.getContentFileName(uri: Uri): String? = runCatching {
    contentResolver.query(uri, null, null, null, null)?.use { cursor ->
        cursor.moveToFirst()
        return@use cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME).let(cursor::getString)
    }
}.getOrNull()

Upvotes: 34

kulikovman
kulikovman

Reputation: 391

This will return the filename from Uri without file extension.

fun Uri.getFileName(): String? {
    return this.path?.let { path -> File(path).name }
}

Here I described a way to get the filename with the extension.

Upvotes: 0

Cloud
Cloud

Reputation: 11

我从开发者官网找到一些信息

I got some information from the developer's website

取得游标

val cursor = context.contentResolver.query(fileUri, null, null, null, null)

接着就可以获取名称和文件大小

val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.moveToFirst()
val fileName = cursor.getString(nameIndex)
val size = cursor.getLong(sizeIndex)

别忘记关闭资源

Don't forget to close resources

Retrieving file information

Upvotes: 0

Manish Kumar Sharma
Manish Kumar Sharma

Reputation: 13432

Combination of all the answers

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 [email protected]/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;
    }
}

Upvotes: 1

artdeell
artdeell

Reputation: 181

The most condensed version:

public String getNameFromURI(Uri uri) {
    Cursor c = getContentResolver().query(uri, null, null, null, null);
    c.moveToFirst();
    return c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}

Upvotes: 16

Mamour Ndiaye
Mamour Ndiaye

Reputation: 21

Please try this :

  private String displayName(Uri uri) {

             Cursor mCursor =
                     getApplicationContext().getContentResolver().query(uri, null, null, null, null);
             int indexedname = mCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
             mCursor.moveToFirst();
             String filename = mCursor.getString(indexedname);
             mCursor.close();
             return filename;
 }

Upvotes: 2

This actually worked for me:

private String uri2filename() {

    String ret;
    String scheme = uri.getScheme();

    if (scheme.equals("file")) {
        ret = uri.getLastPathSegment();
    }
    else if (scheme.equals("content")) {
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            ret = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        }
   }
   return ret;
}

Upvotes: 2

save_jeff
save_jeff

Reputation: 465

If you want to have the filename with extension I use this function to get it. It also works with google drive file picks

public static String getFileName(Uri uri) {
    String result;

    //if uri is content
    if (uri.getScheme() != null && uri.getScheme().equals("content")) {
        Cursor cursor = global.getInstance().context.getContentResolver().query(uri, null, null, null, null);
        try {
            if (cursor != null && cursor.moveToFirst()) {
                //local filesystem
                int index = cursor.getColumnIndex("_data");
                if(index == -1)
                    //google drive
                    index = cursor.getColumnIndex("_display_name");
                result = cursor.getString(index);
                if(result != null)
                    uri = Uri.parse(result);
                else
                    return null;
            }
        } finally {
            cursor.close();
        }
    }

    result = uri.getPath();

    //get filename + ext of path
    int cut = result.lastIndexOf('/');
    if (cut != -1)
        result = result.substring(cut + 1);
    return result;
}

Upvotes: 9

Stefan Michev
Stefan Michev

Reputation: 5093

Stefan Haustein function for xamarin/c#:

public string GetFilenameFromURI(Android.Net.Uri uri)
        {
            string result = null;
            if (uri.Scheme == "content")
            {
                using (var cursor = Application.Context.ContentResolver.Query(uri, null, null, null, null))
                {
                    try
                    {
                        if (cursor != null && cursor.MoveToFirst())
                        {
                            result = cursor.GetString(cursor.GetColumnIndex(OpenableColumns.DisplayName));
                        }
                    }
                    finally
                    {
                        cursor.Close();
                    }
                }
            }
            if (result == null)
            {
                result = uri.Path;
                int cut = result.LastIndexOf('/');
                if (cut != -1)
                {
                    result = result.Substring(cut + 1);
                }
            }
            return result;
        }

Upvotes: 1

Metu
Metu

Reputation: 1093

Easiest ways to get file name:

val fileName = File(uri.path).name
// or
val fileName = uri.pathSegments.last()

If they don't give you the right name you should use:

fun Uri.getName(context: Context): String {
    val returnCursor = context.contentResolver.query(this, null, null, null, null)
    val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    returnCursor.moveToFirst()
    val fileName = returnCursor.getString(nameIndex)
    returnCursor.close()
    return fileName
}

Upvotes: 35

Samuel
Samuel

Reputation: 9993

If you want it short this should work.

Uri uri= data.getData();
File file= new File(uri.getPath());
file.getName();

Upvotes: 17

Vasanth
Vasanth

Reputation: 6375

I use below code to get File Name & File Size from Uri in my project.

/**
 * Used to get file detail from uri.
 * <p>
 * 1. Used to get file detail (name & size) from uri.
 * 2. Getting file details from uri is different for different uri scheme,
 * 2.a. For "File Uri Scheme" - We will get file from uri & then get its details.
 * 2.b. For "Content Uri Scheme" - We will get the file details by querying content resolver.
 *
 * @param uri Uri.
 * @return file detail.
 */
public static FileDetail getFileDetailFromUri(final Context context, final Uri uri) {
    FileDetail fileDetail = null;
    if (uri != null) {
        fileDetail = new FileDetail();
        // File Scheme.
        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
            File file = new File(uri.getPath());
            fileDetail.fileName = file.getName();
            fileDetail.fileSize = file.length();
        }
        // Content Scheme.
        else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            Cursor returnCursor =
                    context.getContentResolver().query(uri, null, null, null, null);
            if (returnCursor != null && returnCursor.moveToFirst()) {
                int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                fileDetail.fileName = returnCursor.getString(nameIndex);
                fileDetail.fileSize = returnCursor.getLong(sizeIndex);
                returnCursor.close();
            }
        }
    }
    return fileDetail;
}

/**
 * File Detail.
 * <p>
 * 1. Model used to hold file details.
 */
public static class FileDetail {

    // fileSize.
    public String fileName;

    // fileSize in bytes.
    public long fileSize;

    /**
     * Constructor.
     */
    public FileDetail() {

    }
}

Upvotes: 11

Bhargav
Bhargav

Reputation: 8277

Taken from Retrieving File information | Android developers

Retrieving a File's name.

private String queryName(ContentResolver resolver, Uri uri) {
    Cursor returnCursor =
            resolver.query(uri, null, null, null, null);
    assert returnCursor != null;
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    returnCursor.moveToFirst();
    String name = returnCursor.getString(nameIndex);
    returnCursor.close();
    return name;
}

Upvotes: 60

Ayaz Alifov
Ayaz Alifov

Reputation: 8588

First, you need to convert your URI object to URL object, and then use File object to retrieve a file name:

try
    {
        URL videoUrl = uri.toURL();
        File tempFile = new File(videoUrl.getFile());
        String fileName = tempFile.getName();
    }
    catch (Exception e)
    {

    }

That's it, very easy.

Upvotes: 2

RenatoIvancic
RenatoIvancic

Reputation: 2092

My version of the answer is actually very similar to the @Stefan Haustein. I found the answer on Android Developer page Retrieving File Information; the information here is even more condensed on this specific topic than on Storage Access Framework guide site. In the result from the query the column index containing file name is OpenableColumns.DISPLAY_NAME. None of other answers/solutions for column indexes worked for me. Below is the sample function:

 /**
 * @param uri uri of file.
 * @param contentResolver access to server app.
 * @return the name of the file.
 */
def extractFileName(uri: Uri, contentResolver: ContentResolver): Option[String] = {

    var fileName: Option[String] = None
    if (uri.getScheme.equals("file")) {

        fileName = Option(uri.getLastPathSegment)
    } else if (uri.getScheme.equals("content")) {

        var cursor: Cursor = null
        try {

            // Query the server app to get the file's display name and size.
            cursor = contentResolver.query(uri, null, null, null, null)

            // Get the column indexes of the data in the Cursor,
            // move to the first row in the Cursor, get the data.
            if (cursor != null && cursor.moveToFirst()) {

                val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                fileName = Option(cursor.getString(nameIndex))
            }

        } finally {

            if (cursor != null) {
                cursor.close()
            }

        }

    }

    fileName
}

Upvotes: 1

user5233139
user5233139

Reputation: 19

String Fpath = getPath(this, uri) ;
File file = new File(Fpath);
String filename = file.getName();

Upvotes: 1

Stefan Haustein
Stefan Haustein

Reputation: 18793

developer.android.com has nice example code for this: https://developer.android.com/guide/topics/providers/document-provider.html

A condensed version to just extract the file name (assuming "this" is an Activity):

public String getFileName(Uri uri) {
  String result = null;
  if (uri.getScheme().equals("content")) {
    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    try {
      if (cursor != null && cursor.moveToFirst()) {
        result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
      }
    } finally {
      cursor.close();
    }
  }
  if (result == null) {
    result = uri.getPath();
    int cut = result.lastIndexOf('/');
    if (cut != -1) {
      result = result.substring(cut + 1);
    }
  }
  return result;
}

Upvotes: 230

Ken Fehling
Ken Fehling

Reputation: 2111

I'm using something like this:

String scheme = uri.getScheme();
if (scheme.equals("file")) {
    fileName = uri.getLastPathSegment();
}
else if (scheme.equals("content")) {
    String[] proj = { MediaStore.Images.Media.TITLE };
    Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
    if (cursor != null && cursor.getCount() != 0) {
        int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE);
        cursor.moveToFirst();
        fileName = cursor.getString(columnIndex);
    }
    if (cursor != null) {
        cursor.close();
    }
}

Upvotes: 50

Sujith S Manjavana
Sujith S Manjavana

Reputation: 1576

public String getFilename() 
{
/*  Intent intent = getIntent();
    String name = intent.getData().getLastPathSegment();
    return name;*/
    Uri uri=getIntent().getData();
    String fileName = null;
    Context context=getApplicationContext();
    String scheme = uri.getScheme();
    if (scheme.equals("file")) {
        fileName = uri.getLastPathSegment();
    }
    else if (scheme.equals("content")) {
        String[] proj = { MediaStore.Video.Media.TITLE };
        Uri contentUri = null;
        Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
        if (cursor != null && cursor.getCount() != 0) {
            int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE);
            cursor.moveToFirst();
            fileName = cursor.getString(columnIndex);
        }
    }
    return fileName;
}

Upvotes: 4

Related Questions