Android 11(SDK30)下载文件夹写入同名文件重复无法覆盖删除问题问询
问题原因
- Android 11(API 30)开始默认强制执行分区存储策略,
WRITE_EXTERNAL_STORAGE权限已经废弃,仅对Android 10及更低版本生效,申请后也无法获得公共目录的直接文件读写权限。 - 你当前的写入逻辑每次都会调用
resolver.insert()向MediaStore插入新的文件记录,当Download目录下存在同名文件时,系统会自动为新插入的文件添加(1)、(2)这类后缀避免重名,不会覆盖原有文件,这是生成多个重名文件的直接原因。 - 两个删除方法均存在逻辑错误:
- 第一个删除方法读取的是
context.getExternalFilesDir()路径,这是应用专属的私有目录,和系统公共Download目录完全不属于同一路径,根本找不到目标文件,自然删除失败。 - 第二个删除方法先调用
insert()生成了一个新的文件URI,再删除这个新创建的URI,不会触及已存在的旧文件,当然没有效果。
- 第一个删除方法读取的是
解决方案
不需要单独做删除操作,只需要调整写入逻辑:写入前先查询MediaStore获取已存在的同名文件URI,存在就直接用该URI写入覆盖,不存在再插入新记录即可。
你可以移除Android 11及以上版本的WRITE_EXTERNAL_STORAGE权限申请逻辑,向公共Download目录写入媒体文件不需要该权限。
下面是修改后的写入代码:
fun writeToFile(applicationContext: Context, filename: String, data: String) { try { val resolver = applicationContext.contentResolver val externalUri = MediaStore.Files.getContentUri("external") // 先查询是否已存在同名文件 val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} = ? " + "AND ${MediaStore.MediaColumns.RELATIVE_PATH} = ?" val selectionArgs = arrayOf( filename, "${Environment.DIRECTORY_DOWNLOADS}/" // 注意末尾要加斜杠匹配系统存储格式 ) var existingUri: Uri? = null resolver.query( externalUri, arrayOf(MediaStore.MediaColumns._ID), selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) existingUri = ContentUris.withAppendedId(externalUri, id) } } val targetUri = existingUri ?: run { // 不存在旧文件,插入新记录 val values = ContentValues() values.put(MediaStore.MediaColumns.DISPLAY_NAME, filename) values.put(MediaStore.MediaColumns.MIME_TYPE, "text/xml") values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) resolver.insert(externalUri, values) } // 写入内容,wt模式会直接覆盖原有内容 targetUri?.let { uri -> resolver.openOutputStream(uri, "wt")?.use { os -> os.write(data.toByteArray()) os.flush() } } } catch (e: FileNotFoundException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } }
内容的提问来源于stack exchange,提问作者Beachdog
相关产品推荐
相关产品推荐

