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

Android

Android Problem Overview


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?

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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

Solution 3 - Android

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

Solution 4 - Android

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
}

Solution 5 - Android

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()

Solution 6 - Android

If you want it short this should work.

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

Solution 7 - Android

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

Solution 8 - Android

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() {

    }
}

Solution 9 - Android

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

Solution 10 - Android

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

Solution 11 - Android

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

Solution 12 - Android

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

Solution 13 - Android

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

Solution 14 - Android

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

Solution 15 - Android

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("/")
        }
    }
}

Solution 16 - Android

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

Solution 17 - Android

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
}

Solution 18 - Android

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.

Solution 19 - Android

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

Solution 20 - Android

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

Solution 21 - Android

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.

Solution 22 - Android

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

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

Solution 23 - Android

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionViktor BrešanView Question on Stackoverflow
Solution 1 - AndroidStefan HausteinView Answer on Stackoverflow
Solution 2 - AndroidKen FehlingView Answer on Stackoverflow
Solution 3 - AndroidBhargavView Answer on Stackoverflow
Solution 4 - AndroidMetuView Answer on Stackoverflow
Solution 5 - AndroidTamim AttafiView Answer on Stackoverflow
Solution 6 - AndroidSamuelView Answer on Stackoverflow
Solution 7 - AndroidartdeellView Answer on Stackoverflow
Solution 8 - AndroidVasanthView Answer on Stackoverflow
Solution 9 - Androidsave_jeffView Answer on Stackoverflow
Solution 10 - AndroidSujith ManjavanaView Answer on Stackoverflow
Solution 11 - AndroidJose Manuel Gomez AlvarezView Answer on Stackoverflow
Solution 12 - AndroidMamour NdiayeView Answer on Stackoverflow
Solution 13 - AndroidOhhhThatVarunView Answer on Stackoverflow
Solution 14 - AndroidWhiteVulpesView Answer on Stackoverflow
Solution 15 - AndroidUdaraWanasingheView Answer on Stackoverflow
Solution 16 - Androiduser5233139View Answer on Stackoverflow
Solution 17 - AndroidRenatoIvancicView Answer on Stackoverflow
Solution 18 - AndroidAyaz AlifovView Answer on Stackoverflow
Solution 19 - AndroidStefan MichevView Answer on Stackoverflow
Solution 20 - AndroidManish Kumar SharmaView Answer on Stackoverflow
Solution 21 - AndroidZharView Answer on Stackoverflow
Solution 22 - AndroidCloudView Answer on Stackoverflow
Solution 23 - AndroidkulikovmanView Answer on Stackoverflow