Kotlin Multiplatform 中使用Ktor实现大文件边下载边存本地的可行性咨询
KMM场景下Ktor大文件下载方案解答
边下载边写入本地的方案完全可行
你不需要将完整文件加载到内存,也不需要自己单独写expect/actual的存储适配逻辑,依托Ktor的流式响应能力+跨平台IO库Okio即可在共享层实现全链路逻辑:
- Ktor客户端的
HttpResponse提供ByteReadChannel可以按块读取响应字节流,无需等待全量数据返回 - 引入支持KMP的Okio依赖后,可直接在共享层通过
FileSystem.SYSTEM操作本地文件,不需要额外做平台适配 - 可以在字节流读取、写入本地的过程中同步计算MD5、更新下载进度,不需要额外的IO操作
50MB文件全加载到内存的方案不推荐
虽然50MB的内存占用在当前中高端机型前台场景下不一定会立刻触发崩溃,但存在明确的性能风险:
- Android端低端机、后台运行场景下可用内存余量极低,50MB的大内存占用很容易触发系统杀进程,甚至直接OOM
- iOS端大内存占用会降低APP的系统优先级,后台下载场景下有极高概率被系统主动终止
- 方案扩展性极差,后续如果业务需要下载更大体积的文件,全量加载的逻辑完全无法复用
共享层核心实现示例
import io.ktor.client.HttpClient import io.ktor.client.call.bodyAsChannel import io.ktor.client.request.get import io.ktor.utils.io.core.readAvailable import okio.FileSystem import okio.buffer import okio.sink import java.security.MessageDigest suspend fun downloadLargeFile( downloadUrl: String, localSavePath: String, // 由平台侧传入各自沙箱内的合法存储路径 serverMd5: String, onProgressUpdate: (progressPercent: Float) -> Unit ): Boolean { val httpClient = HttpClient() return httpClient.get(downloadUrl).bodyAsChannel().use { responseChannel -> val contentTotalLength = responseChannel.contentLength() ?: 0L var totalReadBytes = 0L val buffer = ByteArray(8 * 1024) // 8KB 缓存块,可自行调整 val md5Digest = MessageDigest.getInstance("MD5") // 初始化本地文件写入流 FileSystem.SYSTEM.sink(localSavePath.toPath()).buffer().use { fileSink -> while (!responseChannel.isClosedForRead) { val currentReadBytes = responseChannel.readAvailable(buffer) if (currentReadBytes == -1) break // 写入本地文件 fileSink.write(buffer, 0, currentReadBytes) // 累加计算MD5 md5Digest.update(buffer, 0, currentReadBytes) // 更新进度 totalReadBytes += currentReadBytes if (contentTotalLength > 0) { onProgressUpdate((totalReadBytes.toFloat() / contentTotalLength) * 100f) } } fileSink.flush() } // MD5校验 val calculatedMd5 = md5Digest.digest().joinToString("") { "%02x".format(it) } calculatedMd5.equals(serverMd5, ignoreCase = true) } }
注:路径参数
localSavePath可由双端各自调用原生API获取沙箱存储目录后传入共享层即可,不需要在共享层适配路径权限逻辑。
内容的提问来源于stack exchange,提问作者Roman Gelembjuk
相关产品推荐
相关产品推荐

