Android 10及以上版本如何通过MediaStore编辑文件而非新建?
如何通过MediaStore编辑外部Documents目录下的已有文件?
这问题我之前也踩过坑!你用insert()方法的话,MediaStore的逻辑就是每次都创建新的文件条目,哪怕文件名重复,系统也会自动给新文件加后缀(比如doc (1).txt),所以要编辑原文件的核心是先找到已存在文件的URI,而不是直接插入新条目。
解决思路
- 先通过ContentResolver查询Documents目录下是否存在目标文件
- 如果查询到已存在的URI,就直接打开输出流编辑它;如果没查到,再用原来的
insert()方法创建新文件
修改后的完整代码
val resolver = applicationContext.contentResolver val fileName = "doc.txt" val relativePath = "Documents" val mimeType = "text/plain" // 1. 查询已存在的文件URI var existingUri: Uri? = null val projection = arrayOf(MediaStore.Files.FileColumns._ID) val selection = "${MediaStore.MediaColumns.DISPLAY_NAME} = ? AND ${MediaStore.MediaColumns.RELATIVE_PATH} = ?" val selectionArgs = arrayOf(fileName, "$relativePath/") // RELATIVE_PATH存储时结尾带斜杠,查询要匹配 resolver.query( MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)) existingUri = MediaStore.Files.getContentUri("external").buildUpon() .appendPath(id.toString()) .build() } } // 2. 处理编辑或创建逻辑 val targetUri = existingUri ?: run { val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, fileName) put(MediaStore.MediaColumns.MIME_TYPE, mimeType) put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath) } resolver.insert(MediaStore.Files.getContentUri("external"), contentValues) } targetUri?.let { uri -> // 打开输出流:"w"覆盖原内容,"wa"追加内容 resolver.openOutputStream(uri, "w")?.use { outputStream -> outputStream.write("new line1".toByteArray(Charset.defaultCharset())) outputStream.write("new line2".toByteArray(Charset.defaultCharset())) // use{}会自动关闭流,无需手动调用close() } }
关键细节说明
- 查询
RELATIVE_PATH时,条件里的路径必须以斜杠结尾(比如"Documents/"),因为MediaStore存储的该字段自带结尾斜杠 - 打开输出流的第二个参数控制写入模式:
"w"会清空原文件内容再写入,"wa"会在原内容末尾追加 - 用Kotlin的
use{}包裹流操作,能自动处理资源释放,避免内存泄漏
内容的提问来源于stack exchange,提问作者dgp
相关产品推荐
相关产品推荐

