0

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

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

但是,我不使用 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

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

PS在进一步的进展中,这个SO问题的答案也可能很有趣。

版本数据:

  • 科特林/JVM 1.4.20
  • 克托尔 1.4.1
  • 开放JDK 11
4

1 回答 1

1

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

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
    }
}
于 2021-03-11T10:58:31.620 回答