Android API 29无法读取Download目录文件问题求助
问题原因与解决办法
为什么看不到Download目录的文件?
你用的API29(Android 10)已经启用了分区存储(Scoped Storage),getExternalStoragePublicDirectory这个方法已被废弃,而且即便申请了READ_EXTERNAL_STORAGE权限,普通应用也无法直接读取公共Download目录里的非媒体类文件——系统会限制这种直接访问行为,所以才会出现目录存在但读不出文件的情况。
修复代码的几种方式
方式1:用MediaStore查询媒体文件(仅适用于图片/音频/视频等媒体类型)
如果目标文件是媒体类,可通过MediaStore查询:
fun queryMediaFiles() { val projection = arrayOf( MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DISPLAY_NAME, MediaStore.Files.FileColumns.DATA ) val selection = "${MediaStore.Files.FileColumns.MEDIA_TYPE} != ?" val selectionArgs = arrayOf(MediaStore.Files.FileColumns.MEDIA_TYPE_NONE.toString()) val sortOrder = "${MediaStore.Files.FileColumns.DATE_ADDED} DESC" contentResolver.query( MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, sortOrder )?.use { cursor -> while (cursor.moveToNext()) { val fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME)) // 处理找到的文件 } } }
方式2:用存储访问框架(SAF)让用户选择文件(通用所有文件类型)
这是官方推荐的通用方案,无需特殊权限,让用户手动选择目标文件:
private val REQUEST_CODE_PICK_FILE = 1001 fun openFilePicker() { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) // 设置文件类型,所有文件用"*/*",也可指定如"text/plain" type = "*/*" } startActivityForResult(intent, REQUEST_CODE_PICK_FILE) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE_PICK_FILE && resultCode == Activity.RESULT_OK) { data?.data?.let { uri -> // 通过Uri读取文件内容,复制到应用本地存储 contentResolver.openInputStream(uri)?.use { inputStream -> openFileOutput("target_file_name", Context.MODE_PRIVATE).use { outputStream -> inputStream.copyTo(outputStream) } } } } }
方式3:临时关闭分区存储(仅调试用,不推荐上线)
若只是临时调试,可在AndroidManifest.xml的<application>标签中添加:
android:requestLegacyExternalStorage="true"
这会暂时回到旧存储模式,让原有代码能读取Download目录文件,但该属性在Android 11及以上失效,且不符合官方存储规范,正式上线不建议使用。
替代的文件传输方案
除了邮件下载,还有这些更便捷的方式:
- ADB推送:用命令
adb push 本地文件路径 /sdcard/Download/直接将PC文件传到手机Download目录,再用上述SAF方式读取 - 应用内网络传输:在应用中添加简单的HTTP服务或Socket功能,PC端通过网络直接把文件传到应用内部存储
- 第三方工具中转:用QQ/微信将文件传到手机,再通过SAF在聊天目录中选择文件,复制到应用存储
内容的提问来源于stack exchange,提问作者Mick
相关产品推荐
相关产品推荐

