使用 Ktor HTTP 客户端(和 kotlinx.io?)直接将可恢复的下载到一个文件

Using Ktor HTTP Client (and kotlinx.io?) for resumable downloads directly to a file

我之前没有接触过(大)HTTP 下载,所以我真的不太了解这个话题。

所以,我想做的是以编程方式将文件从 Internet 直接下载到本地文件系统。如果下载是可恢复的,那也很好。对于 Java,我发现 this Baeldung article 基本上解释了如何做到这一点。

不过,我不使用 Java,而是使用 Kotlin。更具体地说,我使用 Ktor HTTP 客户端(带有 Apache 引擎,但如果需要我可以切换它)。我想知道是否有一种方法可以像在提到的文章中那样使用这个客户端。基本上,我会调用 GET 请求,但我会告诉客户端将字节流式传输到指定的 File 位置。下载中断时,我会查询当前状态的文件大小,并在该字节位置(PartialContent)继续下载。

我发现

  1. Ktor 服务器支持这个:https://ktor.io/docs/partial-content.html
  2. kotlinx-io 库可能会有帮助(因为与文章的类比):https://github.com/Kotlin/kotlinx-io

但是,我不知道如何将所有东西放在一起并“连接松散的电线”以使其全部正常工作。看来我的问题对于简单的 google 搜索来说太具体了,这就是我现在求助于 SO 的原因。如果任何对 Ktor 和 HTTP 下载有一定经验的人可以为我阐明这一点,我将不胜感激!

PS在进一步的进展中,对的回答可能也很有趣。

版本数据:

基本思想是通过发出 HEAD 请求来获取总内容长度,然后在 Range header 的帮助下迭代下载内容。这是一个示例实现:

suspend fun main() {
    val client = HttpClient()
    client.download(
        "https://weq714976.live-website.com/wp-content/uploads/2019/03/WeQ-Influencers-Logo-1568x812.png",
        File("result.png")
    )
}

suspend fun HttpClient.download(url: String, outFile: File, chunkSize: Int = 1024) {
    val length = head<HttpResponse>(url).headers[HttpHeaders.ContentLength]?.toLong() as Long
    val lastByte = length - 1

    var start = outFile.length()
    val output = FileOutputStream(outFile, true)

    while (true) {
        val end = min(start + chunkSize - 1, lastByte)

        get<HttpResponse>(url) {
            header("Range", "bytes=${start}-${end}")
        }.content.copyTo(output)

        if (end >= lastByte) break

        start += chunkSize
    }
}