Scoped Storage Stories: DocumentFile
Android 10 is greatly restricting access to external storage via filesystem APIs. Instead, we need to use other APIs to work with content. This is the third post in a series where we will explore how to work with those alternatives, starting with the Storage Access Framework (SAF).
Whether you use ACTION_OPEN_DOCUMENT or ACTION_CREATE_DOCUMENT, you wind up
with a Uri that points to the “document”. Your primary use of that Uri is
with ContentResolver and its openInputStream() and openOutputStream() methods,
so you can read and/or write the document. This is not that different from having
a File and using the FileInputStream and FileOutputStream constructors to
be able to read and/or write the document.
However, File has a lot of other useful methods, such as:
-
getName()to get the filename -
exists()to confirm that an actual file exists at the path wrapped by theFile -
delete()to delete the file -
and so on
The way to get similar functionality for your document Uri is
via DocumentFile.
DocumentFile can wrap a File or a document Uri and give you an API that
resembles a subset of File functionality, including the three methods that I listed
above.
If you have a document Uri, you can wrap it in a DocumentFile via
DocumentFile.fromSingleUri(). You can then call getName(), exists(), delete(),
and other methods, such as:
-
getType()to get the MIME type associated with the content -
length()to get the length of the content (i.e., how many bytes you could read in from theInputStream) -
renameTo()to rename the content -
and so on
However, there are some limitations:
-
The “name” for a piece of content is not necessarily a filename with an extension. It is a “display name”, and it should be something that the user might recognize. However, if you are expecting
SomethingLike-This.png, you may be disappointed. The display name might be a classic filename, but it does not have to be. -
canWrite()is somewhat broken, in that it may returntruefor aUrithat you cannot write to
Note that you can also get a DocumentFile for a File via DocumentFile.fromFile().
This allows you to treat document Uri values and files the same, so that portions
of your app can be written independently of where the data comes from.
The entire series of “Scoped Storage Stories” posts includes posts on:
- The basics of using the Storage Access Framework
- Getting durable access to the selected content
- Working with
DocumentFilefor individual documents - Working with document trees
- Working with
DocumentsContract - Problems with the SAF API
- A specific problem with
listFiles()onDocumentFile - Storing content using
MediaStore - Reading content from the
MediaStore - Modifying
MediaStorecontent from other apps - Limitations of
MediaStore.Downloads - The undocumented
Documentsoption - More on
RecoverableSecurityException - How to modify more metadata in
MediaStore

