'How to access files in a directory given a content URI?
My question is very similar to this question. I got content Uri of a directory using ACTION_OPEN_DOCUMENT_TREE. and got something like this
content://com.android.externalstorage.documents/tree/primary%3ASHAREit%2Fpictures
as result upon selecting a directory. Now, my problem is how can i access all the files inside the directory (and preferably subdirectories too).
Solution 1:[1]
Use DocumentFile.fromTreeUri() to create a DocumentFile for your tree. Then, use listFiles() to get a list of the documents and sub-trees inside of that tree. For those where isDirectory() returns true, you can further traverse the tree. For the rest, use getUri() to get a Uri to the document, which you can use with openInputStream() on a ContentResolver to get the content, if needed.
Solution 2:[2]
I am very new to Android Development, and was stuck on understanding CommonsWare's answer (among other resources) for a long time. This resource was also helpful.
- You need the DocumentFile AndroidX library, so add that to your
build.gradle:
implementation "androidx.documentfile:documentfile:1.0.1"
- Once you've gotten your content URI which contains the
tree, you can useDocumentFile.fromTreeUri
val filenamesToDocumentFile = mutableMapOf<String, DocumentFile>()
val documentsTree = DocumentFile.fromTreeUri(context, treeUri) ?: return
val childDocuments = documentsTree.listFiles()
for (childDocument in childDocuments) {
childDocuments[0].name?.let {
filenamesToDocumentFile[it] = childDocument
}
}
Now I'm off to figure out how to use this DocumentFile... (hint: val inputStream = contentResolver.openInputStream(childDocument.uri))
Solution 3:[3]
Here a snippet related to @CommonsWare answer.
Launch the file picker with Intent.ACTION_OPEN_DOCUMENT_TREE
startActivityForResult(
Intent.createChooser(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), "Choose directory"),
IMPORT_FILE_REQUEST
)
Receive the Uri of the selected directory from file picker
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
IMPORT_FILE_REQUEST -> {
if (resultCode != Activity.RESULT_OK) return
val uri = data?.data ?: return
// get children uri from the tree uri
val childrenUri =
DocumentsContract.buildChildDocumentsUriUsingTree(
uri,
DocumentsContract.getTreeDocumentId(uri)
)
// get document file from children uri
val tree = DocumentFile.fromTreeUri(this, childrenUri)
// get the list of the documents
tree?.listFiles()?.forEach { doc ->
// get the input stream of a single document
val iss = contentResolver.openInputStream(doc.uri)
// prepare the output stream
val oss = FileOutputStream(File(filesDir, doc.name))
// copy the file
CopyFile { result ->
println("file copied? $result")
}.execute(iss, oss)
}
}
}
}
Copy file with AsyncTask (feel free to use threads, coroutines..)
class CopyFile(val callback: (Boolean) -> Unit) :
AsyncTask<Closeable, Int, Boolean>() {
override fun doInBackground(vararg closeables: Closeable): Boolean {
if (closeables.size != 2) throw IllegalArgumentException("two arguments required: input stream and output stream")
try {
(closeables[0] as InputStream).use { iss ->
(closeables[1] as OutputStream).use { oss ->
iss.copyTo(oss)
return true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
override fun onPostExecute(result: Boolean) {
callback.invoke(result)
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | CommonsWare |
| Solution 2 | cmak |
| Solution 3 | fireb86 |
