Android中能否通过content uri路径创建File?如何满足S3上传需求
解决方案
错误原因
你拿到的是content://开头的Content URI,属于Android内容提供者提供的资源标识,不是设备本地文件的绝对路径。File类仅支持处理本地文件系统路径,所以直接传入Content URI创建File对象必然失败。Glide内部适配了Content URI的读取逻辑,因此可以正常加载图片。
实现方案
方案1:将Content URI内容拷贝到应用私有目录生成File(兼容所有版本)
该方案是官方推荐的分区存储兼容方案,不会受到系统版本权限限制。
- 首先实现URI转File的工具方法:
fun uriToFile(context: Context, uri: Uri, targetFile: File): File? { return runCatching { context.contentResolver.openInputStream(uri)?.use { inputStream -> targetFile.outputStream().use { outputStream -> inputStream.copyTo(outputStream) } } targetFile }.getOrNull() }
- 可额外实现获取原文件名的工具方法,避免文件后缀错误:
fun getFileNameFromUri(context: Context, uri: Uri): String? { return context.contentResolver.query(uri, null, null, null, null)?.use { cursor -> if (cursor.moveToFirst()) { cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) } else null } }
- 调用示例:
// 将字符串格式的Content URI转为Uri对象 val contentUri = Uri.parse(path) // 选择应用可访问的存储目录,优先用外部缓存目录,没有则用内部缓存目录 val storageDir = context.externalCacheDir ?: context.cacheDir // 获取原文件名,也可以自定义文件名 val fileName = getFileNameFromUri(context, contentUri) ?: "upload_${System.currentTimeMillis()}.jpg" val targetFile = File(storageDir, fileName) // 执行拷贝获取最终可用的File对象 val uploadFile = uriToFile(context, contentUri, targetFile) // 判空后即可将uploadFile封装为MultipartBody.Part上传
方案2:直接通过输入流创建RequestBody(无需生成临时文件)
如果不需要保留本地文件,可以直接读取Content URI的输入流创建RequestBody,节省存储空间:
fun createRequestBodyFromUri(context: Context, uri: Uri): RequestBody? { return runCatching { val inputStream = context.contentResolver.openInputStream(uri) ?: return@runCatching null object : RequestBody() { override fun contentType() = context.contentResolver.getType(uri)?.toMediaTypeOrNull() override fun contentLength() = inputStream.available().toLong() override fun writeTo(sink: BufferedSink) { inputStream.use { sink.writeAll(it.source()) } } } }.getOrNull() }
调用该方法拿到RequestBody后,可直接创建MultipartBody.Part用于上传。
注意事项
- Android 10及以上版本禁止直接访问公共媒体文件的真实路径,不要尝试通过查询MediaStore的DATA字段获取真实路径,该方案已被官方废弃
- 需要提前申请对应权限:Android 13+申请
READ_MEDIA_IMAGES权限,Android 12及以下申请READ_EXTERNAL_STORAGE权限 - 方案1生成的临时文件如果后续不需要使用,建议及时删除避免占用存储空间
内容的提问来源于stack exchange,提问作者hanjiman
相关产品推荐
相关产品推荐

