如何在KMM中使用Ktor高效上传1GB及以上大文件
在KMM中使用Ktor流式上传大文件(1GB+)的解决方案
核心思路
Ktor支持流式上传,无需将整个文件加载到内存(彻底避免内存溢出和效率低下问题)。由于KMM通用代码无法直接访问平台特定的File类(Android的Java File、iOS的NSFile),我们可以通过expect/actual机制封装平台相关的文件流读取逻辑,在通用代码中统一使用Ktor的Input类型完成上传。
步骤实现
1. 定义通用层的文件流读取接口
在commonMain中声明expect函数,用于跨平台获取文件的流式输入:
import io.ktor.utils.io.Input expect suspend fun getFileInput(filePath: String): Input
2. 实现平台特定的文件流读取
Android平台(androidMain)
利用Java File类读取文件通道,转换为Ktor的Input:
import io.ktor.utils.io.Input import io.ktor.utils.io.readChannel import java.io.File actual suspend fun getFileInput(filePath: String): Input { val file = File(filePath) if (!file.exists()) error("目标文件不存在:$filePath") return file.readChannel().toInput() }
iOS平台(iosMain)
利用iOS的NSInputStream读取文件,转换为Ktor的Input:
import io.ktor.utils.io.Input import io.ktor.utils.io.toInput import platform.Foundation.NSInputStream import platform.Foundation.NSURL actual suspend fun getFileInput(filePath: String): Input { val fileUrl = NSURL.fileURLWithPath(filePath) val inputStream = NSInputStream.inputStreamWithURL(fileUrl) ?: error("无法打开文件流:$filePath") inputStream.open() return inputStream.toInput() }
3. 通用代码中实现流式上传
在通用层调用上述函数获取文件流,通过Ktor的formData完成上传:
import io.ktor.client.HttpClient import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse import io.ktor.http.HttpHeaders import io.ktor.http.content.formData import io.ktor.http.content.headers // 初始化Ktor客户端(根据平台配置对应引擎,如Android用OkHttp、iOS用Darwin) val ktorClient = HttpClient { // 可添加序列化、日志等插件 } suspend fun uploadLargeFile(filePath: String, uploadEndpoint: String): HttpResponse { val fileInput = getFileInput(filePath) val fileName = filePath.substringAfterLast("/") // 提取文件名 return ktorClient.post(uploadEndpoint) { // 可选:监听上传进度 onUpload { bytesSentTotal, contentLength -> val progress = bytesSentTotal.toDouble() / contentLength.toDouble() // 此处可更新UI或记录上传进度 } setBody(formData { append( key = "file", value = fileInput, headers = headers { append(HttpHeaders.ContentDisposition, "form-data; name=\"file\"; filename=\"$fileName\"") append(HttpHeaders.ContentType, "application/octet-stream") // 根据文件类型调整 } ) // 可附加其他表单字段 append("uploadSource", "KMM") }) } }
关键说明
- 流式上传优势:使用
Input类型时,Ktor会逐块读取文件内容并发送,不会将整个文件加载到内存,完全适配1GB+的大文件上传场景。 - 平台兼容性:
expect/actual机制屏蔽了平台文件API的差异,通用代码无需关心底层实现细节。 - 进度监听:通过
onUpload回调可以实时获取上传进度,方便实现进度条等交互功能。
内容的提问来源于stack exchange,提问作者Jagdish Jangir
相关产品推荐
相关产品推荐

