Android : Convert Uri object to File [duplicate] - android
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.
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)
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);
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)
}
}
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;
}
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
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
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
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
you can use this funtion for get file from uri in new android and older
fun getFileFromUri(context: Context, uri: Uri?): File? {
uri ?: return null
uri.path ?: return null
var newUriString = uri.toString()
newUriString = newUriString.replace(
"content://com.android.providers.downloads.documents/",
"content://com.android.providers.media.documents/"
)
newUriString = newUriString.replace(
"/msf%3A", "/image%3A"
)
val newUri = Uri.parse(newUriString)
var realPath = String()
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (newUri.path?.contains("/document/image:") == true) {
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1])
} else {
databaseUri = newUri
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 = realPath.ifEmpty {
when {
newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace(
"/document/raw:",
""
)
newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace(
"/document/primary:",
"/storage/emulated/0/"
)
else -> return null
}
}
return if (path.isNullOrEmpty()) null else File(path)
}
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)
Related
Can not get file on android API 29 up
I can not read a file that I'm saving. I have declared and asking for storage permissions. fun saveImage(bitmap: Bitmap, context: Context): String { if (android.os.Build.VERSION.SDK_INT >= 29) { val values = contentValues() values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + context.getString(R.string.app_name)) values.put(MediaStore.Images.Media.IS_PENDING, true) // RELATIVE_PATH and IS_PENDING are introduced in API 29. val uri: Uri? = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values).also { uri -> if (uri != null) { if (uri != null) { saveImageToStream(bitmap, context.contentResolver.openOutputStream(uri)) values.put(MediaStore.Images.Media.IS_PENDING, false) context.contentResolver.update(uri, values, null, null) } //val split = file.path.split(":".toRegex()).toTypedArray() //split the path. Log.d( "Tag", "v--- uri.path - ${uri.path}, " ) return uri.path.toString() //assign it to a string(your choice). } } } else { // below API 29 } } then in onCreate or any other method I want to access that file and show on preview. val previousPath = """/external/images/media/356""" //preferenceManager.getString(...) //val file = File(path) //previewImage.setImageURI(Uri.parse(previousPath)) val file = FileUtils().getFile(applicationContext, Uri.parse(previousPath)) Log.d("Tag", "Yo --- "+file?.path + " , "+ file?.name) // val myBitmap = BitmapFactory.decodeFile() // previewImage.setImageBitmap() But this is always empty. With this getFile method, I get null pointer exception. I need the file to upload to server. How can I get this file?
val uri: Uri? = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) You used that obtained uri to save your file content to storage with: context.contentResolver.openOutputStream(uri) Now if you wanna read that file use the same uri again. Just use: context.contentResolver.openInputStream(uri) Use the same uri! Dont mess around with the File class.
how can access to video path in my device?
#Throws(IOException::class) private fun createVideoFile(): File { // Create an image file name val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_MOVIES) return File.createTempFile( "oogoo_${timeStamp}_", ".mp4", storageDir ).apply { videoPath = this.path videoUri = this.toUri() } } Iam using CameraView to record Video . when stop record I get path of record D/VideoTaken: /storage/emulated/0/Android/data/com.example.testgogoapplication/files/Movies/oogoo_20211021_125639_3062139219833544197.mp4 file:///storage/emulated/0/Android/data/com.example.testgogoapplication/files/Movies/oogoo_20211021_125639_3062139219833544197.mp4 put not found this path in Device how can access to this path?. if there is another way to save the video to storage (best way to write file) by Kotlin
Use this: private fun createVideoOutputPath(context: Context): String { val contentResolver = context.contentResolver /** Represent the videos collection */ val videosCollection: Uri = sdkAndUp(29) { // if sdk is 29 or higher MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) } ?: MediaStore.Video.Media.EXTERNAL_CONTENT_URI /** Represents the data values of the video to be saved */ val contentValues = ContentValues() // Adding the file title to the content values contentValues.put( MediaStore.Video.Media.TITLE, "VID_" + System.currentTimeMillis() + ".mp4" ) // Adding the file display name to the content values contentValues.put( MediaStore.Video.Media.DISPLAY_NAME, "VID_" + System.currentTimeMillis() + ".mp4" ) /** Represents the uri of the inserted video */ val videoUri = contentResolver.insert(videosCollection, contentValues)!! // Opening a stream on to the content associated with the video content uri contentResolver.openOutputStream(videoUri) /** Represents the file path of the video uri */ val outputPath = getUriRealPath(context, videoUri)!! // Deleting the video uri to create it later with the actual video contentResolver.delete(videoUri, null, null) return outputPath } private fun getUriRealPath(contentResolver: ContentResolver, uri: Uri): String { var filePath = "" val cursor = contentResolver.query(uri, null, null, null, null) if (cursor != null) { if (cursor.moveToFirst()) { var columnName = MediaStore.Images.Media.DATA when (uri) { MediaStore.Images.Media.EXTERNAL_CONTENT_URI -> { columnName = MediaStore.Images.Media.DATA } MediaStore.Video.Media.EXTERNAL_CONTENT_URI -> { columnName = MediaStore.Video.Media.DATA } } val filePathColumnIndex = cursor.getColumnIndex(columnName) filePath = cursor.getString(filePathColumnIndex) } cursor.close() } return filePath } This code inserts a video uri to MediaStore, retrieves its file path, and removes it from MediaStore. This path will be to the Movies directory which is public and does not require permissions. Now you can use this file path to create a File object like so: val file = File(createVideoOutputPath(context))
I can't fetch documents from the downloads folder in android
I am trying to attach documents from download folder. But i am getting the error "java.io.FileNotFoundException: /storage/emulated/0/DownloadReact-native commands.pdf (No such file or directory)".Here i show the code that i used to get path. if (isDownloadsDocument(uri)) { Log.d("build_version_one", Build.VERSION.SDK_INT.toString()) Log.d("build_version_two", Build.VERSION_CODES.M.toString()) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val id: String var cursor: Cursor? = null try { cursor = context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null) if (cursor != null && cursor.moveToFirst()) { val fileName = cursor.getString(0) // val path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName val path = Environment.getExternalStorageDirectory().toString() +"/Download" + fileName val ss = Environment.getExternalStoragePublicDirectory("").toString()+"/Download" + fileName Log.d("orginal_path","one"+path) Log.d("orginal_path","two"+ss) if (!TextUtils.isEmpty(path)) { Log.d("orginal_path","working") return path } } } finally { cursor?.close() } id = DocumentsContract.getDocumentId(uri) if (!TextUtils.isEmpty(id)) { if (id.startsWith("raw:")) { return id.replaceFirst("raw:".toRegex(), "") } val contentUriPrefixesToTry = arrayOf( "content://downloads/public_downloads", "content://downloads/my_downloads" ) for (contentUriPrefix in contentUriPrefixesToTry) { return try { val contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), java.lang.Long.valueOf(id)) Log.d("orginal_content_uri", contentUri.toString()) /* final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));*/ getDataColumn(context, contentUri, null, null) } catch (e: NumberFormatException) { //In Android 8 and Android P the id is not a number uri.path.replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "") } } } } }
As the Exception states, there is no such file/directory available on your disk or path provided is incorrect. At the first glance, it seems you missed a slash between filename and Download directory /storage/emulated/0/DownloadReact-native commands.pdf. Make sure you have a slash between filename and a path. val path = Environment.getExternalStorageDirectory().toString() +"/Download/" + fileName val ss = Environment.getExternalStoragePublicDirectory("").toString()+"/Download/" + fileName See if it works. Otherwise verify if you file in the respective directory.
getExternalStorageDirectory deprecated in API level 29 java. Use getExternalFilesDir(), getExternalCacheDir(), or getExternalMediaDir() (methods on Context).
File found using android MediaStore but BitmapFactory unable to decode it with path returned from MediaStore
I have searched high and low and not found an answer to my particular question, I hope someone can help. I am developing this for Android 9 and above, the code I use for older releases works fine. It's quite simple, I have stored an image in the MediaStore, I have found the image in the media store, I return its path, I check the path exists and it does, it also has a correct size and is visible in the android Gallery. So why when I try to open it with val bitmap2 = BitmapFactory.decodeFile(fullPath) bitmap2 comes back as null - no errors are generated by the above command. The parseAllImages function was taken from the web and tweaked slightly but seems to work ok as far as I can tell. sample code private fun setPic() { if (mediaPath.isNotEmpty()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val content = GalleryAdd.parseAllImages(requireActivity(), mediaPath) val fullPath = content if (File(fullPath).exists()) { val tester = File(fullPath).length() val bitmap2 = BitmapFactory.decodeFile(fullPath) viewModel.setBitmap(bitmap2) } } } } fun parseAllImages(act : Activity, name : String) : String { try { val projection = arrayOf(MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID) val cursor = act.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, // Which columns to return null, // Return all rows null, null ) val size: Int = cursor!!.getCount() /******* If size is 0, there are no images on the SD Card. */ if (size == 0) { } else { val thumbID = 0 if (cursor != null) { while (cursor.moveToNext()) { val file_ColumnIndex: Int = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) /**************** Captured image details */ /***** Used to show image on view in LoadImagesFromSDCard class */ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val path: String = cursor.getString(file_ColumnIndex) val fileName = path.substring(path.lastIndexOf("/") + 1, path.length) if (fileName == name) { return path } } } } } catch (e: Exception) { e.printStackTrace() } return "" } Code snippet I use to write to the media store if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val resolver: ContentResolver = activity.contentResolver val contentValues = ContentValues() contentValues.put( MediaStore.MediaColumns.DISPLAY_NAME, fileName ) contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg") contentValues.put( MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + "fishy" ) val imageUri: Uri? = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) val tester = imageUri.toString() + File.separator + Environment.DIRECTORY_PICTURES + File.separator + "fishy" + File.separator + fileName scanLoc = fileName fos = resolver.openOutputStream(imageUri!!)!! val file = File(currentPhotoPath) val ins: InputStream = file.inputStream() ins.copyTo(fos) } Any help or can someone point me to sample code that can read a jpg image from the mediastore given it's name? It's not production ready so please forgive lack of error checks. Thanks Lee.
Android: Getting a file URI from a content URI?
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.
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)
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);
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) } }
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; }
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
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
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
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
you can use this funtion for get file from uri in new android and older fun getFileFromUri(context: Context, uri: Uri?): File? { uri ?: return null uri.path ?: return null var newUriString = uri.toString() newUriString = newUriString.replace( "content://com.android.providers.downloads.documents/", "content://com.android.providers.media.documents/" ) newUriString = newUriString.replace( "/msf%3A", "/image%3A" ) val newUri = Uri.parse(newUriString) var realPath = String() val databaseUri: Uri val selection: String? val selectionArgs: Array<String>? if (newUri.path?.contains("/document/image:") == true) { databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI selection = "_id=?" selectionArgs = arrayOf(DocumentsContract.getDocumentId(newUri).split(":")[1]) } else { databaseUri = newUri 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 = realPath.ifEmpty { when { newUri.path?.contains("/document/raw:") == true -> newUri.path?.replace( "/document/raw:", "" ) newUri.path?.contains("/document/primary:") == true -> newUri.path?.replace( "/document/primary:", "/storage/emulated/0/" ) else -> return null } } return if (path.isNullOrEmpty()) null else File(path) }
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)