Android: Getting a file URI from a content URI?

AndroidFileUri

Android Problem Overview


In my app the user is to select an audio file which the app then handles. The problem is that in order for the app to do what I want it to do with the audio files, I need the URI to be in file format. When I use Android's native music player to browse for the audio file in the app, the URI is a content URI, which looks like this:

content://media/external/audio/media/710

However, using the popular file manager application Astro, I get the following:

file:///sdcard/media/audio/ringtones/GetupGetOut.mp3

The latter is much more accessible for me to work with, but of course I want the app to have functionality with the audio file the user chooses regardless of the program they use to browse their collection. So my question is, is there a way to convert the content:// style URI into a file:// URI? Otherwise, what would you recommend for me to solve this problem? Here is the code which calls up the chooser, for reference:

Intent ringIntent = new Intent();
ringIntent.setType("audio/mp3");
ringIntent.setAction(Intent.ACTION_GET_CONTENT);
ringIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(ringIntent, "Select Ringtone"), SELECT_RINGTONE);

I do the following with the content URI:

m_ringerPath = m_ringtoneUri.getPath();
File file = new File(m_ringerPath);

Then do some FileInputStream stuff with said file.

Android Solutions


Solution 1 - Android

Just use getContentResolver().openInputStream(uri) to get an InputStream from a URI.

http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.Uri)

Solution 2 - Android

This is an old answer with deprecated and hacky way of overcoming some specific content resolver pain points. Take it with some huge grains of salt and use the proper openInputStream API if at all possible.

You can use the Content Resolver to get a file:// path from the content:// URI:

String filePath = null;
Uri _uri = data.getData();
Log.d("","URI = "+ _uri);										
if (_uri != null && "content".equals(_uri.getScheme())) {
    Cursor cursor = this.getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
	cursor.moveToFirst();	
    filePath = cursor.getString(0);
    cursor.close();
} else {
	filePath = _uri.getPath();
}
Log.d("","Chosen path = "+ filePath);

Solution 3 - Android

Try this....

get File from a content uri

fun fileFromContentUri(context: Context, contentUri: Uri): File {
    // Preparing Temp file name
    val fileExtension = getFileExtension(context, contentUri)
    val fileName = "temp_file" + if (fileExtension != null) ".$fileExtension" else ""

    // Creating Temp file
    val tempFile = File(context.cacheDir, fileName)
    tempFile.createNewFile()

    try {
        val oStream = FileOutputStream(tempFile)
        val inputStream = context.contentResolver.openInputStream(contentUri)

        inputStream?.let {
            copy(inputStream, oStream)
        }

        oStream.flush()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    return tempFile
}

private fun getFileExtension(context: Context, uri: Uri): String? {
    val fileType: String? = context.contentResolver.getType(uri)
    return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType)
}

@Throws(IOException::class)
private fun copy(source: InputStream, target: OutputStream) {
    val buf = ByteArray(8192)
    var length: Int
    while (source.read(buf).also { length = it } > 0) {
        target.write(buf, 0, length)
    }
}

Solution 4 - Android

If you have a content Uri with content://com.externalstorage... you can use this method to get absolute path of a folder or file on Android 19 or above.

public static String getPath(final Context context, final Uri uri) {
	final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

	// DocumentProvider
	if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
		System.out.println("getPath() uri: " + uri.toString());
		System.out.println("getPath() uri authority: " + uri.getAuthority());
		System.out.println("getPath() uri path: " + uri.getPath());

		// ExternalStorageProvider
		if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
			final String docId = DocumentsContract.getDocumentId(uri);
			final String[] split = docId.split(":");
			final String type = split[0];
			System.out.println("getPath() docId: " + docId + ", split: " + split.length + ", type: " + type);

			// This is for checking Main Memory
			if ("primary".equalsIgnoreCase(type)) {
				if (split.length > 1) {
					return Environment.getExternalStorageDirectory() + "/" + split[1] + "/";
				} else {
					return Environment.getExternalStorageDirectory() + "/";
				}
				// This is for checking SD Card
			} else {
				return "storage" + "/" + docId.replace(":", "/");
			}

		}
	}
	return null;
}

You can check each part of Uri using println. Returned values for my SD card and device main memory are listed below. You can access and delete if file is on memory, but I wasn't able to delete file from SD card using this method, only read or opened image using this absolute path. If you find a solution to delete using this method, please share.

SD CARD

getPath() uri: content://com.android.externalstorage.documents/tree/612E-B7BF%3A/document/612E-B7BF%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/612E-B7BF:/document/612E-B7BF:
getPath() docId: 612E-B7BF:, split: 1, type: 612E-B7BF

MAIN MEMORY

getPath() uri: content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/primary:/document/primary:
getPath() docId: primary:, split: 1, type: primary

If you wish to get Uri with file:/// after getting path use

DocumentFile documentFile = DocumentFile.fromFile(new File(path));
documentFile.getUri() // will return a Uri with file Uri

Solution 5 - Android

Inspired answers are Jason LaBrun & Darth Raven. Trying already answered approaches led me to below solution which may mostly cover cursor null cases & conversion from content:// to file://

To convert file, read&write the file from gained uri

public static Uri getFilePathFromUri(Uri uri) throws IOException {
    String fileName = getFileName(uri);
    File file = new File(myContext.getExternalCacheDir(), fileName);
    file.createNewFile();
    try (OutputStream outputStream = new FileOutputStream(file);
         InputStream inputStream = myContext.getContentResolver().openInputStream(uri)) {
        FileUtil.copyStream(inputStream, outputStream); //Simply reads input to output stream
        outputStream.flush();
    }
    return Uri.fromFile(file);
}

To get filename use, it will cover cursor null case

public static String getFileName(Uri uri) {
    String fileName = getFileNameFromCursor(uri);
    if (fileName == null) {
        String fileExtension = getFileExtension(uri);
        fileName = "temp_file" + (fileExtension != null ? "." + fileExtension : "");
    } else if (!fileName.contains(".")) {
        String fileExtension = getFileExtension(uri);
        fileName = fileName + "." + fileExtension;
    }
    return fileName;
}

There is good option to converting from mime type to file extention

 public static String getFileExtension(Uri uri) {
    String fileType = myContext.getContentResolver().getType(uri);
    return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType);
}

Cursor to obtain name of file

public static String getFileNameFromCursor(Uri uri) {
    Cursor fileCursor = myContext.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
    String fileName = null;
    if (fileCursor != null && fileCursor.moveToFirst()) {
        int cIndex = fileCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        if (cIndex != -1) {
            fileName = fileCursor.getString(cIndex);
        }
    }
    return fileName;
}

Solution 6 - Android

Trying to handle the URI with content:// scheme by calling ContentResolver.query()is not a good solution. On HTC Desire running 4.2.2 you could get NULL as a query result.

Why not to use ContentResolver instead? https://stackoverflow.com/a/29141800/3205334

Solution 7 - Android

Well I am bit late to answer,but my code is tested

check scheme from uri:

 byte[] videoBytes;

if (uri.getScheme().equals("content")){
        InputStream iStream =   context.getContentResolver().openInputStream(uri);
            videoBytes = getBytes(iStream);
        }else{
            File file = new File(uri.getPath());
            FileInputStream fileInputStream = new FileInputStream(file);     
            videoBytes = getBytes(fileInputStream);
        }

In the above answer I converted the video uri to bytes array , but that's not related to question, I just copied my full code to show the usage of FileInputStream and InputStream as both are working same in my code.

I used the variable context which is getActivity() in my Fragment and in Activity it simply be ActivityName.this

context=getActivity(); //in Fragment

context=ActivityName.this;// in activity

Solution 8 - Android

you can use this funtion for get file from uri in new android and older

fun getFileFromUri(uri: Uri): File? {
    if (uri.path == null) {
        return null
    }
    var realPath = String()
    val databaseUri: Uri
    val selection: String?
    val selectionArgs: Array<String>?
    if (uri.path!!.contains("/document/image:")) {
        databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        selection = "_id=?"
        selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
    } else {
        databaseUri = uri
        selection = null
        selectionArgs = null
    }
    try {
        val column = "_data"
        val projection = arrayOf(column)
        val cursor = context.contentResolver.query(
            databaseUri,
            projection,
            selection,
            selectionArgs,
            null
        )
        cursor?.let {
            if (it.moveToFirst()) {
                val columnIndex = cursor.getColumnIndexOrThrow(column)
                realPath = cursor.getString(columnIndex)
            }
            cursor.close()
        }
    } catch (e: Exception) {
        Log.i("GetFileUri Exception:", e.message ?: "")
    }
    val path = if (realPath.isNotEmpty()) realPath else {
        when {
            uri.path!!.contains("/document/raw:") -> uri.path!!.replace(
                "/document/raw:",
                ""
            )
            uri.path!!.contains("/document/primary:") -> uri.path!!.replace(
                "/document/primary:",
                "/storage/emulated/0/"
            )
            else -> return null
        }
    }
    return File(path)
}

Solution 9 - Android

You can use the following android package which can be easier a bit for you

https://github.com/Blankj/AndroidUtilCode

Using the above package the code can be like

To Import use below Line > import com.blankj.utilcode.util.UriUtils;

Your code can be like

File f = UriUtils.uri2File(result);

Thanks

Solution 10 - Android

you can get filename by uri with simple way

Retrieving file information

fun get_filename_by_uri(uri : Uri) : String{
    contentResolver.query(uri, null, null, null, null).use { cursor ->
        cursor?.let {
            val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            it.moveToFirst()
            return it.getString(nameIndex)
        }
    }
    return ""
}

and easy to read it by using

contentResolver.openInputStream(uri)

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
QuestionJMRboostiesView Question on Stackoverflow
Solution 1 - AndroidJason LeBrunView Answer on Stackoverflow
Solution 2 - AndroidRafael NobreView Answer on Stackoverflow
Solution 3 - AndroidShaonView Answer on Stackoverflow
Solution 4 - AndroidThracianView Answer on Stackoverflow
Solution 5 - AndroidMuhammed Yalçın KuruView Answer on Stackoverflow
Solution 6 - AndroidDarth RavenView Answer on Stackoverflow
Solution 7 - AndroidUmar AtaView Answer on Stackoverflow
Solution 8 - AndroidMahdi ZareeiView Answer on Stackoverflow
Solution 9 - AndroidMahesh MahiView Answer on Stackoverflow
Solution 10 - AndroidandermirikView Answer on Stackoverflow