如何获取路径 /storage/emulated/0/Download/file_name.mime_type 适用于 Android 10 及更高版本

问题描述

我正在设备 Downloads(Android 11) 目录中保存一个文件,以便我的应用稍后查看。我允许多种文件类型,如 pdfword 等。我能够像这样保存文件:(我从 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 的配置根

我从 IDquerycursor 得到这个 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"