I want to show a file browser to the user, let him choose an arbitrary file he wants, and read it using the ZipFile class. The class requires a File object, not an InputStream.
If my research is correct, the in-built file choosers (ACTION_OPEN_DOCUMENT, etc) only provide a stream, not a File, right? Even if I get the file name from the chooser and have acquired READ_EXTERNAL_STORAGE from the user, it seems that in recent Android versions, the API only allows "only media" and reading files of other types seems to fail.
If I have also acquired MANAGE_EXTERNAL_STORAGE, then it works, but that shows a scary warning like following to the user.
Allow this app to access, modify, and delete files on the device or any connected storage devices? This app may access files without asking you.
That seems to be an unnecessarily broad permission when all I want to is a read-only access to File
for a file that the user has explicitly chosen in the file browser. There is no other way than acquiring MANAGE_EXTERNAL_STORAGE, is that right? I want to make it sure, because it sounds weird. Even a very restricted environment like a web browser, the browser does not require any special permission or show any warning for reading a file that the user has explicitly selected, and the same was true for UWP app.
CodePudding user response:
If my research is correct, the in-built file choosers (ACTION_OPEN_DOCUMENT, etc) only provide a stream, not a File, right?
Correct. After all, the user can choose something that you cannot access via the filesystem, either due to permissions or due to the fact that it simply isn't on the filesystem (e.g., cloud storage, SMB/CIFS file server).
IOW, what you refer to as "file choosers" are not limited to what you seem to be thinking of as files.
If I have also acquired MANAGE_EXTERNAL_STORAGE, then it works
I do not know what "it" is. You cannot hack into Google Drive to get a File
object using MANAGE_EXTERNAL_STORAGE
, for example. Nor can you get a File
object for a document contained as a BLOB in an encrypted database, etc.
There is no other way than acquiring MANAGE_EXTERNAL_STORAGE, is that right?
You cannot do what you want even with MANAGE_EXTERNAL_STORAGE
. A Uri
is not a file.
Your options are:
Copy the content identified by the
Uri
to some file that you control (e.g., ingetCacheDir()
), so you can useZipFile
.Relax the
ZipFile
constraint. For example, perhaps you could useZipInputStream
, or find a third-party ZIP reader that supportsInputStream
(such as this or this). You can get anInputStream
on the content identified by theUri
viaopenInputStream()
onContentResolver
.Relax the "in-built file choosers" constraint, and implement your own "file chooser" with files that your app can read on the filesystem. That way, you are guaranteed that you can use
File
, since you usedFile
to get to them in the first place.