现在,当我从我的应用程序中选择要上传的文件时,例如照片
private val imageFileFromGalleryPickResult =
registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { imageUri ->
imageUri?.let { }
}
然后我将它保存到应用程序个人存储(缓存目录),如果您需要修改它(更改分辨率或在发送到服务器之前修复方向),这很有用
suspend fun savePublicFileToAppCacheDir(context: Context, fileUri: Uri): File {
val appCacheDir = ContextCompat.getExternalCacheDirs(context)
.filterNotNull()
.first()
.also { it.mkdirs() }
val file = File(appCacheDir, "temp_file.jpg")
context.contentResolver.openInputStream(uri)!!.use { input ->
FileOutputStream(file).use { output ->
output.write(input.readBytes())
}
}
return file
}
在那之后我可以很容易地用
Retrofit2
发送这个文件因为应用程序拥有它:
fun buildMultipartBodyPart(file: File, paramName: String): MultipartBody.Part {
val requestFile = file.asRequestBody("image/jpeg".toMediaTypeOrNull())
return MultipartBody.Part.createFormData(paramName, file.name, requestFile)
}
@Multipart
@POST("user/profile/photo")
suspend fun sendProfilePhoto(
@Part photoFile: MultipartBody.Part,
)
但是我没有先复制到应用程序目录的文件呢,尤其是大文件(50mb+)?
所以我只有
Uri
。那么我怎样才能用 Retrofit 发送文件呢?以某种方式发送InputStream
?
更新
我想我只能用
fun ByteArray.toRequestBody()
来input.readBytes()
但是,大文件呢? :)
现在我是这样实现的:
fun Uri.getFileName(
context: Context,
contentResolver: ContentResolver = context.contentResolver
): String? {
val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
contentResolver.query(this, projection, null, null, null)?.use {
if (it.moveToFirst()) {
return it.getString(0)
}
}
return null
}
fun Uri.toMultipartBodyPart(
context: Context,
paramName: String
): MultipartBody.Part {
val uri = this
val contentResolver = context.contentResolver
val fileName = uri.getFileName(context, contentResolver)
val mimeType = contentResolver.getType(uri)
val bytes = contentResolver.openInputStream(uri)!!.use { input ->
input.readBytes() // not good for RAM
}
val requestedBody = bytes.toRequestBody(mimeType?.toMediaTypeOrNull())
return MultipartBody.Part.createFormData(paramName, fileName, requestedBody)
}
如果有更好的方法,很高兴在这里看到其他带有示例的答案