Get path from URI throws exception - java

I have an Android application that i'm working on and now i'm trying to get a File from an URI (i'll use an intent to get an image from gallery and then upload it to a node.js server using Ion). Te problem is it always throws an exception. I tried debugging and got the Uri.toString(). It looks something kind of like this:
content://com.android.providers.media.documents/document/image%3A102
I know for a fact that it should look like this:
content://com.android.providers.media.documents/document/image:102
I know that the %3A is a representation of :, but why does it appear in the Uri and, how can i fix it? Finally, how can i get my file from this Uri?

i'm trying to get a File from an URI
A Uri is not a file. A Uri does not have to point to anything on the filesystem, let alone a place that you can access.
but why does it appear in the Uri
A Uri is an opaque handle. It can be whatever the ContentProvider wants it to be.
how can i fix it?
You don't, any more than you "fix" https://stackoverflow.com/questions/41795342/get-path-from-uri-throws-exception because you do not like eight-digit numbers starting with 4. Just as the Stack Overflow Web server defines that URLs it uses, so does a ContentProvider define what Uri values it uses.
Finally, how can i get my file from this Uri?
Ideally, you don't. You use ContentResolver and openInputStream() to get an InputStream on the content identified by that Uri, and Ion uses that.
If Ion does not support this and can only work with a file, use the InputStream to copy the bytes to some FileOutputStream that you control (e.g., in getCacheDir()). Use that file for your upload, then delete the file when you are done.

Related

How to get the actual source path in Struts 2?

I have a little problem with Struts 2 when I try to get the context path :
ServletActionContext.getServletContext().getRealPath("\\WebContent\\resources\\img\\");
I got this path:
C:\Users\killian\workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\SiteWebAdministrable\WebContent\resources\imgicone.jpg
Why the exact source path ?
Because i need to upload and save images for an admin website to control background and without the actual path i cannot save images in the resources path...
So i save the path with the name and extension in the database (no problem), and i need to save the image in the resource directory (image problem...)
Can someone help me please ? Did i forgot something ?
This question is the answer ?
How do you get the project path in Struts 2?
servletContext.getServletContext().getRealPath("/resources/img/name_of_image.png")
So, passing the "/" to getRealPath() would return you the absolute disk file system path of the /web folder of the expanded WAR file of the project. Something like /path/to/server/work/folder/demo.war/ which you should be able to further use in File or FileInputStream.
Note that most starters don't seem to see/realize that you can actually pass the whole web content path to it and that they often use
String absolutePathToIndexJSP = servletContext.getRealPath("/") + "demo.png";
instead of
String absolutePathToIndexJSP = servletContext.getRealPath("/demo.png");
getRealPath() is unportable; you'd better never use it
Use getRealPath() carefully.
If all you actually need is to get an InputStream of the web resource, better use ServletContext#getResourceAsStream() instead, this will work regardless of the way how the WAR is expanded. So, if you for example want an InputStream of index.jsp, then do not do:
InputStream input = new FileInputStream(servletContext.getRealPath("/demo.png")); // Wrong!
But instead do:
InputStream input = servletContext.getResourceAsStream("/demo.png"); // Right!
Or if you intend to obtain a list of all available web resource paths, use ServletContext#getResourcePaths() instead.
Set<String> resourcePaths = servletContext.getResourcePaths("/");

How to know whether writing to stream would result in java.io.IOException: write failed: EBADF (Bad file number)

I know there are a number of posts here on the java.io.IOException: write failed: EBADF (Bad file number) exception, but non of them seems to answer my particular question:
Suppose my activity is called with Intent.ACTION_VIEW and I got a Uri via Uri uri = intent.getData() that starts with content:// from which I read some data (for example a pdf file). Now I want to find out whether I can also write to that Uri to decide whether a "save" button should be shown to the user, or just a "save as" button.
Suppose further that I can successfully open first a ParcelFileDescriptor and finally a FileOutputStream as in
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
such that fileOutputStream != null.
Depending on the Uri it can now happen that if I try to write to fileOutputStream I get the exception:
Exception=java.io.IOException: write failed: EBADF (Bad file number)
I would like to know in advance whether this will happen without actually touching/changing the file. One would think that it should be possible to find out whether I can write to a given Uri or not before trying.
How can I achieve that?
Additional observations:
I suppose that the above happens when I don't have permission to write to that particular file/uri, but then why does Android let me open a FileOutputStream in the first place?
For testing I use attachments in emails received with Kaiten mail on an ICS device. If I my app opens after I click on "save" in Kaiten mail uri matches content://media/external/file/[0-9]* and everything works, if I however clicked on "open" uri matches content://com.kaitenmail.attachmentprovider/[-0-9a-f]*/[0-9]*/VIEW and I run into the above error.
The correct way to test whether any resource is available is to try to use it, and handle the exceptions or errors that result when you can't.
Anything else amounts to fortune-telling. You might
test the wrong thing
test the right thing but get an answer that is correct for the time of the test but not for the time of the actual use. This can work two ways, both bad: the test says you can't, but later you could: or the test says you can, but later you can't.
Don't try to predict the future. Coping with the present is difficult enough.
There are apparently two methods:
One can call
Context.checkCallingUriPermission(Uri uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
to check whether the calling process is allowed to write to a given Uri.
For the cases I could check, on API level < 19 this seems to result in PackageManager.PERMISSION_DENIED whenever the writing to an output stream pointing to uri fails and in PackageManager.PERMISSION_GRANTED in all other cases.
For API level >= 19 it however yields PackageManager.PERMISSION_DENIED even if one has previously taken a persisted write permission with getContentResolver().takePersistableUriPermission(Uri uri, int takeFlags). In that case however one can use
context.getContentResolver().getPersistedUriPermissions()
to get a list of all previously taken permissions and then look through them so see if one has permission to write to a given Uri.
If one got he Uri via an Intent intent one can check its flags via intent.getFlags() and see whether Intent.FLAG_GRANT_WRITE_URI_PERMISSION is set. This also seems to be a way to "predict the future".
Obviously, neither of the above methods can be an excuse to not properly handle exceptions that can occur while writing to the stream.

Loading an image from the Resource Folder

The code I am using to load the image is:
ImageIO.read(SpriteSheet.class.getResource(path));
The path being the path to the resource. But it would error with IllegalArgumentException. I wondered what might be causing and came to the conclusion that the resource should be added into the same path as the class.
Is it possible to load the image from another folder, like a res folder outside of the bin folder? (folder holding compiled classes)
EDIT:
So i messed around with a few things, and came to a solution. But now I have another problem. Here is my code
File sheet = new File(SpriteSheet.class.getProtectionDomain().getCodeSource().getLocation().getPath());
URI uri = sheet.toURI();
BufferedImage image = ImageIO.read(uri.toURL());
When I try to run it, it gives me an IIOException: Can't read Input File
This means that I can never actually get it work. I tried debugging by prining the URL to the console and this is the URL.
C:\Users\Amma\Abhijeet\Eclipse%20Workspace1\Test%20Game\bin
The %20 comes in the middle. Meaning that the file is and never can be acceesed. Is there anyway I can fix this?
Thanks.
Class.getResource will return null if the resource could not be found or the invoker doesn't have adequate privileges to get the resource.
All variants of ImageIO.read will throw an IllegalArgumentException if they receive a null input.
Take a look at the documentation of the getResource to understand how an absolute resource name is constructed from the given resource named and what are the rules for searching resources.
You can read images from any location as long as you have permissions to do so, the ImageIO.read method accepts a File, URL or InputStream so you have many option to do it.

AudioInputStream not working

When I embed my resource and use the follwoing:
getClass().getResourceAsStream("sound.wav")
I get the following:
could not get audio input stream from input stream
If I link directly to the file it works fine.
If I link directly to the file it works fine.
It seems that you mean File or URL by that. (Can you confirm that & which one you mean, if so?) In that case, you'll often find that Java Sound requires a repositionable InputStream, which is (strangely) not what getResourceAsStream() returns.
The solution to that problem is to load the sound from URL. Obtain the URL using something like:
URL urlToClip = this.getClass().getResource("sound.wav");
// sanity check!
System.out.println("urlToClip: " + urlToClip);

file: URIs and Slashes

An application I'm working on involves accessing files on network file shares, and we're using URIs to specify the files' locations.
My understanding of the file: URI is that they should take the form of file://+path. In the case of a Windows network share, this path looks something like \\servername\dir\file, so the resultant URI becomes file:////servername/dir/file.
This seems to be working great for Java's URI class, but the Win32 API seems to want a file://servername/dir/file style URI, which Java rejects because it "has an authority component".
Am I understanding network-share URIs correctly? Is there another way to specify a path without Java complaining about the authority?
Edit: We were hoping to be able to store paths as URIs, so as to make use of the scheme-part of the URI to specify other locations (e.g. file: versus other:). But as pointed out, it looks like Java may just have its own issues with URIs...
It seems that Java is wrong:
Incorrect: file:////applib/products/a%2Db/abc%5F9/4148.920a/media/start.swf
Correct: file://applib/products/a-b/abc_9/4148.920a/media/start.swf
On UNC paths in Java:
The URI class handles UNC paths reasonably well, but has some problems. In the Java class libraries, the string representation of a UNC path is as follows:
new File("//SERVER/some/path").toURI().toString()
-> "file:////SERVER/some/path
In other words, the URI stores the entire UNC path in the path component of the URI, and leaves the server/authority component empty. As long as you consistently use this string representation you will be able to interact successfully with java.net.URI.

Categories

Resources