What might the cause of getColumnIndexOrThrow that would throw an exception of
java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []
yet if you rename the file and retry again, it works?
private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String[] projection = {
MediaStore.Files.FileColumns.DATA
};
try {
cursor = context.getContentResolver().query(
uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int cindex = cursor.getColumnIndexOrThrow(projection[0]);
return cursor.getString(cindex);
}
}
catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
the original file comes in the intent of
content://com.sec.android.app.myfiles.FileProvider/device_storage/Download/myfile.pdf
yet the renamed file comes in as
content://0#media/external/file/588
This MediaStore.Files.FileColumns.DATA is deprecated and column '_data' doesn't exist anymore.
As Android Developer stated
This constant was deprecated in API level 29.
Apps may not have filesystem permissions to directly access this path.
Instead of trying
to open this path directly, apps should use
ContentResolver#openFileDescriptor(Uri, String) to gain access.
How To use openFileDescriptor?
i try to bring examples of 2 different widely use files in across application
Image Files
if(uri==null)return;
ContentResolver contentResolver = getActivity().getContentResolver();
if(contentResolver==null)return;
ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
if(fileDescriptor==null)return;
Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
There are a lot of examples of how to handle bitmap
Non-Image Files
if(uri==null)return;
ContentResolver contentResolver = getActivity().getContentResolver();
if(contentResolver==null)return;
ParcelFileDescriptor parcelFileDescriptor = contentResolver.openFileDescriptor(uri,"rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
if(fileDescriptor==null)return;
FileInputStream fileInputStream = new FileInputStream(fileDescriptor);
FileOutputStream fileOutputStream = new FileOutputStream(fileDescriptor);
parcelFileDescriptor.close();
There are a lot of examples of how to handle FileInputStream and FileOutputStream
Conclusion
There is no sense trying to get absolute Path although it isn't necessary unless raising security & privacy issues.Indeed, Relative path is enough for working with files and there are Abstract Representation implementations between kernel Mode and User Mode that can Map Relative Path to Absolute Path and User doesn't need to know.
openFileDescriptor is very fast and compatible to all android versions
Related
I am testing app on nexus 5 which has marshmallow version of android. I am looked into several method to get file path from uri but all the time it returns null. This method works for me on jelly bean and also on kitkat but not on marshmallow.
public String getPath(Uri uri) {
Log.d(TAG,"Uri GET PATH "+uri);
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
Log.d(TAG,"Cursor value "+cursor);
int Column_Index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
Log.d(TAG,"Column Index "+Column_Index);
cursor.moveToFirst();
String ImagePath = cursor.getString(Column_Index);
Log.d(TAG,"ImagePath of "+ImagePath);
cursor.close();
return ImagePath;
}
I also tried this this and also so many others but getting file path from uri is always null.
Uri return from Intent:content://com.android.providers.media.documents/document/image%3A2304`
I am looked into several method to get file path from uri but all the time it returns null
There is no file path. A Uri is not a file.
Use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. Either use that InputStream directly, or use it and a FileOutputStream on some file that you control (e.g., in getCacheDir()) to copy the content to the file, then use the resulting file.
I have a method below:
private String getRealPathFromUriForVideos(Uri selectedVideoUri) {
String wholeID = DocumentsContract.getDocumentId(selectedVideoUri);
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Video.Media.DATA };
String sel = MediaStore.Video.Media._ID + "=?";
Cursor cursor = getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
This works just fine getting the file for videos that hte user selects. However, I want to allow users to also create new videos (from my app) and then get the URI and the file from there. The URI for newly created videos is: content://media/external/video/media/41. For selected videos is like content://com.android.providers.media.documents/document/video%3A42.
It works with the second one but not the first one. First one I get IllegalArgumentException because its not a document URI. How can I get the file from the first URI?
This works just fine getting the file for videos that hte user selects
It may work in a few situations. It will not work in general. A Uri that you get from something like ACTION_OPEN_DOCUMENT does not have to represent a file, let alone one that you can access via the filesystem, let alone one that this script-kiddie algorithm will let you access.
The URI for newly created videos is: content://media/external/video/media/41
Not necessarily. I suppose that there is a way that you get a Uri like that for a recorded video, though off the top of my head I cannot think of a recommended way that would give you such a Uri. If you are using MediaRecorder or ACTION_VIDEO_CAPTURE, you create your own file (and, for ACTION_VIDEO_CAPTURE, your own Uri for that file). And, if you are creating your own file, you know where that file is.
Need to be able to upload to my server
For the video, record to a file that you control, then use that file.
Use some library that lets you upload from a Uri or InputStream. Otherwise:
Use ContentResolver and openFileInput() to get an InputStream on the content represented by the Uri
Create a FileOutputStream on some file that you control (e.g., in getCacheDir())
Copy the content from the InputStream to the OutputStream
Use your copy for the upload
Delete your copy when the work is done
You treat a foreign Uri as if it were a URL to a Web server: stream the content.
Seems to get it from the second URI I need this:
private String getRealPathFromUriForImagesAndVideo(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e) {
return contentUri.getPath();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
i am implementing the functionality to save file in my app which is being sent by some exteral application.
i have provided support for single and mulitple files. Provided handling for all kind of files.
But i am not able to handle the following scenario.
I view a file from an email client -> View it in QuickOffice -> Click on send -> Choose my app->Then click on save in my app.
In that i get the path in following wrapped in the exception
java.io.FileNotFoundException: /file:/data/data/com.qo.android.sp.oem/files/temp/Error.log: open failed: ENOENT (No such file or directory)
I have seen this post which is quite useful for handling uri which has content scheme
Get filename and path from URI from mediastore
Below is my code
Uri uri = (Uri) iterator.next();
if ("content".equals(uri.getScheme())) {
filePath = getFilePathFromContentUri(uri, hostAcitvity.getContentResolver());
}
else {
filePath = uri.getPath();
}
fileName = uri.getLastPathSegment();
fileSize = hostAcitvity.getContentResolver().openInputStream(uri).available();
Code for getFilePathFromContentUri
private String getFilePathFromContentUri(Uri selectedVideoUri, ContentResolver contentResolver)
{
String filePath;
String[] filePathColumn = { MediaColumns.DATA };
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
Then i wrap the path in a FileInputStream which is throwing the above exception
Not able to resolve the file path properly. Is this the correct way of finding the path ?
cheers,
Saurav
I have seen this post which is quite useful for handling uri which has content scheme
That never worked reliably and will work even less reliably in the future.
Is this the correct way of finding the path ?
No, because there is no requirement that every Uri map to a path on a filesystem that you can access.
Use getInputStream() on ContentResolver to get an InputStream on the Uri, and consume the data that way.
When I select an image from the gallery, I grab the intent Uri via the parameter that is passed by the onActivityResult. When doing: new File(String_Uri_given_to_me) and do File.Exists(), gives me null...
What I can do?
It seems you may try:
new File(Uri_given_to_you.getpath())
It may be okay.
If answer above doesn't solve your problem use this code
private final synchronized String getPath(Uri uri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, proj,
null, null, null);
if (cursor.moveToFirst()) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
I was having a hard time with this issue. I was not able to get some images Path (Even using Maxim Efivmov code) and finally decided to use Google's documentation on this topic. https://developer.android.com/guide/topics/providers/document-provider.html
This piece of code worked to get the bitmap
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
You can use this bitmap to display it in an Image View.
I'm writing an app that can be sent a photo URI from the "Share via" menu in Android.
The kind of URI you get is content://media/external/images/media/556 however ExifInterface wants a standard file name. So how do I read the exif data (I just want orientation) of that file? Here's my (non-working) code:
Uri uri = (Uri)extras.getParcelable(Intent.EXTRA_STREAM);
ContentResolver cr = getContentResolver();
InputStream is = cr.openInputStream(uri);
Bitmap bm = BitmapFactory.decodeStream(is);
// This line doesn't work:
ExifInterface exif = new ExifInterface(uri.toString());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Any help (other than "you have to write your own ExifInterface class") is appreciated!
I found the answer randomly in the Facebook Android SDK examples. I haven't tested it, but it looks like it should work. Here's the code:
public static int getOrientation(Context context, Uri photoUri) {
/* it's on the external media. */
Cursor cursor = context.getContentResolver().query(photoUri,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
int result = -1;
if (null != cursor) {
if (cursor.moveToFirst()) {
result = cursor.getInt(0);
}
cursor.close();
}
return result;
}
You can get an ExifInterface using a filename string or InputStream, by doing importing the support ExifInterface in your build.gradle file:
compile 'com.android.support:exifinterface:26.1.0'
then:
private getExifInterfaceFromUri(Uri uri) throws IOException{
FileInputStream fi = new FileInputStream(uri.getPath());
return new ExifInterface(stream);
}
Remember that in Android there are multiple Uri types and you may need to use a Content Resolver and other approaches to get the real path from an Uri.