如何更有效地通过 http 下载大文件?

我正在尝试在 Kotlin 中下载大文件(<1GB),因为我已经知道我在使用 okhttp 并且几乎遵循了这个问题的答案。除了我使用 Kotlin 而不是 java,所以语法略有不同。


val client = OkHttpClient()

val request = Request.Builder().url(urlString).build()

val response = client.newCall(request).execute()


val is = response.body().byteStream()


val input = BufferedInputStream(is)

val output = FileOutputStream(file)


val data = ByteArray(1024)

val total = 0L

val count : Int

do {

    count = input.read(data)

    total += count

    output.write(data, 0, count)

} while (count != -1)


output.flush()

output.close()

input.close()

它的工作原理是它在不使用太多内存的情况下下载文件,但它似乎不必要地无效,因为它不断尝试写入更多数据而不知道是否有新数据到达。在资源非常有限的 VM 上运行它时,我自己的测试似乎也证实了这一点,因为它似乎使用了更多的 CPU,同时下载速度低于 python 中的类似脚本,并且原因使用wget.


我想知道是否有一种方法可以让我在 x 字节可用时调用回调,或者它是否是文件的末尾,这样我就不必在不知道是否存在的情况下不断尝试获取更多数据是任何。


编辑:如果 okhttp 不可能,我使用其他东西没有问题,只是它是我习惯的 http 库。


猛跑小猪
浏览 280回答 2
2回答

浮云间

从版本 11 开始,Java 有一个内置的HttpClient实现具有非阻塞背压的异步数据流如果您希望代码仅在有数据要处理时运行,这就是您所需要的。如果您有能力升级到 Java 11,您将能够使用HttpResponse.BodyHandlers.ofFile正文处理程序开箱即用地解决您的问题。您不必自己实现任何数据传输逻辑。科特林示例:fun main(args: Array<String>) {&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; val client = HttpClient.newHttpClient()&nbsp; &nbsp; val request = HttpRequest.newBuilder()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .uri(URI.create("https://www.google.com"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GET()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .build()&nbsp; &nbsp; println("Starting download...")&nbsp; &nbsp; client.send(request, HttpResponse.BodyHandlers.ofFile(Paths.get("google.html")))&nbsp; &nbsp; println("Done with download.")}

慕慕森

可以取消 BufferedInputStream。或者因为 Oracle 的 java 中的默认缓冲区大小是 8192,所以使用更大的 ByteArray,比如 4096。但是最好是使用 java.nio 或尝试 Files.copy:Files.copy(is,&nbsp;file.toPath());这将删除大约 12 行代码。另一种方法是发送带有标头的请求以压缩gzip压缩Accept-Encoding: gzip,因此传输所需的时间更少。在这里的响应is中new GZipInputStream(is),当Content-Encoding: gzip给出响应标头时,可能会包含在- 中。或者,如果可行,存储压缩的文件,并附加结尾.gz;mybiography.md作为mybiography.md.gz。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java