问题描述
我正在设备 Downloads
的 (Android 11)
目录中保存一个文件,以便我的应用稍后查看。我允许多种文件类型,如 pdf
、word
等。我能够像这样保存文件:(我从 here 获得了此代码示例)
@TargetApi(29)
private suspend fun downloadQ(
url: String,filename: String,mimeType: String
) =
withContext(dispatchers.IO) {
val response = ok.newCall(Request.Builder().url(url).build()).execute()
if (response.isSuccessful) {
val values = ContentValues().apply {
put(MediaStore.Downloads.disPLAY_NAME,filename)
put(MediaStore.Downloads.MIME_TYPE,mimeType)
put(MediaStore.Downloads.IS_PENDING,1)
}
val resolver = context.contentResolver
val uri =
resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,values)
uri?.let {
resolver.openOutputStream(uri)?.use { outputStream ->
val sink = outputStream.sink().buffer()
response.body()?.source()?.let { sink.writeall(it) }
sink.close()
}
values.clear()
values.put(MediaStore.Downloads.IS_PENDING,0)
resolver.update(uri,values,null,null)
} ?: throw RuntimeException("MediaStore Failed for some reason")
} else {
throw RuntimeException("OkHttp Failed for some reason")
}
}
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)
val id = cursor.getLong(idColumn)
Log.d("uri id ","$id")
val contentUri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI,id)
java.lang.IllegalArgumentException: 无法找到包含 /external/downloads/78 的配置根
我从 ID
和 query
从 cursor
得到这个 ContentResolver.query()
(这里是 78),我希望它返回 Uri
,我可以从中得到获取文件。
第二种方法是这样的:
val uri = MediaStore.Downloads.getContentUri("external",id)
uri.path?.let { filePath ->
Log.d("uri path ",filePath)
val file = File(filePath)
} ?: Log.d("uri path ","null")
我使用 external
作为基于 this 答案的目录,但这种方法也抛出了相同的异常
java.lang.IllegalArgumentException: 无法找到包含 /external/downloads/78 的配置根
最后,在我使用文件浏览器应用程序查看确切的目录路径后,最终工作的是硬编码:
val file = File("storage/emulated/0/Download/$name.$extension")
所以我的问题是,如何动态获取此路径的值,并且此路径对于所有可以这样使用的设备都相同吗?
编辑:我还想知道我是否正在使用 filename
并且它是 extension
查看文件,然后如果用户下载另一个同名文件,那么我如何确保正确的文件是开放的? (即使我在 Download
中为我的应用程序创建了一个单独的目录,用户仍然可以两次下载名称类似 storage/emulated/0/Download/myDir/file(2).extension
的同一个文件)
解决方法
试试下面的代码,它会对你有所帮助。
private fun readFile(){
val FILENAME = "user_details.txt"
val dir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.toString() + "/" + "folderName"
)
} else {
File(
Environment.getExternalStorageDirectory()
.toString() + "/${Environment.DIRECTORY_DOWNLOADS}/" + "folderName"
)
}
dir.apply {
if(this.exists()) File(this,FILENAME).apply {
FileInputStream(this).apply {
val stringBuffer = StringBuffer()
var i: Int
while (this.read().also { i = it } != -1) {
stringBuffer.append(i.toChar())
}
close()
}
}
}
}
,
你可以使用
{Environment.DIRECTORY_DOWNLOADS} + "/folderName/file_name.mime_type"