Android中使用Ktor Client分片发送大视频至服务器的实现方案
大视频分片上传实现方案(基于Ktor Client)
核心思路
将大视频文件按固定大小分割为多个分片,通过Ktor Client依次向服务器发送每个分片;所有分片上传完成后,通知服务器合并分片为完整文件。同时加入可靠性机制(重试、断点续传、校验)确保上传成功率。
具体实现步骤
1. 本地文件分片处理
先确定分片大小(建议10MB~50MB,平衡请求次数和单请求大小),然后循环读取文件的每个分片内容:
import java.io.File import kotlin.math.min val videoFile = File("/path/to/your-large-video.mp4") val chunkSize = 10 * 1024 * 1024 // 10MB 分片大小 val totalChunks = (videoFile.length() + chunkSize - 1) / chunkSize // 向上取整计算总分片数 // 遍历每个分片 for (chunkIndex in 0 until totalChunks.toInt()) { val startPos = chunkIndex * chunkSize val endPos = min(startPos + chunkSize, videoFile.length()) val chunkBytes = videoFile.readBytes(startPos.toInt(), (endPos - startPos).toInt()) // 调用上传函数发送当前分片 uploadChunkWithRetry(chunkBytes, videoFile.name, chunkIndex, totalChunks) } // 所有分片上传完成后请求合并 requestMerge(videoFile.name, totalChunks)
2. Ktor Client分片上传实现
配置Ktor Client,每个分片以二进制流形式发送,通过请求头传递分片元数据(文件名、索引、总分片数等):
import io.ktor.client.* import io.ktor.client.engine.okhttp.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.timeout.* import io.ktor.client.request.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json // 初始化Ktor Client,添加超时和JSON解析支持 val ktorClient = HttpClient(OkHttp) { install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) } install(HttpTimeout) { requestTimeoutMillis = 30 * 1000 // 请求超时30秒 connectTimeoutMillis = 10 * 1000 // 连接超时10秒 } } // 单分片上传函数 suspend fun uploadChunk(chunkBytes: ByteArray, fileName: String, chunkIndex: Int, totalChunks: Long) { val response = ktorClient.post("https://your-server-domain/upload/chunk") { contentType(ContentType.Application.OctetStream) setBody(chunkBytes) headers { append("X-File-Name", fileName) append("X-Chunk-Index", chunkIndex.toString()) append("X-Total-Chunks", totalChunks.toString()) // 可选:添加文件全局哈希,用于服务器最终校验完整性 append("X-File-Hash", calculateFileHash(videoFile)) } } // 校验上传是否成功 if (!response.status.isSuccess()) { throw RuntimeException("分片 ${chunkIndex+1}/${totalChunks} 上传失败,状态码:${response.status.value}") } } // 请求服务器合并分片 suspend fun requestMerge(fileName: String, totalChunks: Long) { val response = ktorClient.post("https://your-server-domain/upload/merge") { contentType(ContentType.Application.Json) setBody(mapOf( "fileName" to fileName, "totalChunks" to totalChunks, "fileHash" to calculateFileHash(videoFile) )) } if (!response.status.isSuccess()) { throw RuntimeException("合并请求失败,状态码:${response.status.value}") } } // 辅助函数:计算文件哈希(示例用MD5) fun calculateFileHash(file: File): String { return file.inputStream().use { input -> java.security.MessageDigest.getInstance("MD5").digest(input.readBytes()) .joinToString("") { "%02x".format(it) } } }
3. 可靠性增强机制
- 重试逻辑:对上传失败的分片自动重试,可通过自定义循环实现:
suspend fun uploadChunkWithRetry(chunkBytes: ByteArray, fileName: String, chunkIndex: Int, totalChunks: Long, maxRetries: Int = 3) { var retryCount = 0 while (retryCount < maxRetries) { try { uploadChunk(chunkBytes, fileName, chunkIndex, totalChunks) return } catch (e: Exception) { retryCount++ if (retryCount == maxRetries) throw e // 重试前按次数递增延迟 kotlinx.coroutines.delay(1000 * retryCount) } } } - 断点续传:本地记录已成功上传的分片索引(比如存在SharedPreferences或本地文件),下次上传时跳过已完成的分片。
- 分片校验:服务器返回分片的哈希值,客户端比对本地计算的分片哈希,确保传输完整性。
优化建议
- 若业务允许,可改为并发上传(控制并发数,避免服务器压力过大),但需确保服务器支持乱序接收分片。
- 添加上传进度监听:通过Ktor的
ProgressListener跟踪每个分片的上传进度,更新UI或日志。 - 分片大小可根据网络动态调整:比如弱网环境下减小分片大小,提升成功率。
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

