问题
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.
回答1:
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.
回答2:
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 touri
fails and inPackageManager.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 withgetContentResolver().takePersistableUriPermission(Uri uri, int takeFlags)
. In that case however one can usecontext.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 anIntent intent
one can check its flags viaintent.getFlags()
and see whetherIntent.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.
来源:https://stackoverflow.com/questions/32089745/how-to-know-whether-writing-to-stream-would-result-in-java-io-ioexception-write