我花了太多时间试图解决这个问题。因此,我在下面发布的代码在下载文件方面确实有效,但问题是,该流程具有非常意外的行为。这response.content.readAvailable()
方法调用似乎会阻塞,直到完全下载整个文件,此时发出进度发生,因此您最终会等待很长时间才能下载文件,然后在一瞬间获得所有进度更新。所以我想知道是否有办法做到这一点,我一次读取一定数量的字节,然后发出进度,然后重复直到文件下载完成?或者也许是一种挂钩 readAvailable() 方法并以这种方式更新进度的方法?任何对此的帮助将不胜感激。
这是我找到并修改的代码,但仍然无法正常工作:
suspend fun HttpClient.downloadFile(
output: File,
downloadUrl: String,
md5Hash: String,
) = flow {
try {
val response = get<HttpResponse> { url(downloadUrl) }
val data = ByteArray(response.contentLength()?.toInt() ?: 0)
val contentLn = response.contentLength()?.toInt() ?: 0
var offset = 0
var bytesRemaining = contentLn
do {
val chunkSize = min(maxChunkSize, bytesRemaining)
logger?.d { "Read Available:" }
val result = response.content.readAvailable(data, offset, length = chunkSize)
val progress = ((offset / contentLn.toDouble()) * 100).toInt()
emit(DownloadResult.Progress(progress))
logger?.d { "logged progress: $progress" }
// delay(6000L) this was to test my assumption that the readAvalible was blocking.
offset += chunkSize
bytesRemaining -= chunkSize
} while (result != -1)
if (response.status.isSuccess()) {
if (data.md5().hex == md5Hash) {
output.write(data)
emit(DownloadResult.Success)
} else {
emit(DownloadResult.ErrorCorruptFile)
}
} else {
emit(DownloadResult.ErrorBadResponseCode(response.status.value))
}
} catch (e: TimeoutCancellationException) {
emit(DownloadResult.ErrorRequestTimeout("Connection timed out", e))
}
}
最后经过一段愚蠢的时间我解决了这个问题。你需要使用的是this。这使您可以在下载时访问字节通道。
一个非常粗略的实现(我还没有完成)是这样的:
get<HttpStatement>(url = downloadUrl).execute {
var offset = 0
val byteBufferSize = 1024 * 100
val channel = it.receive<ByteReadChannel>()
val contentLen = it.contentLength()?.toInt() ?: 0
val data = ByteArray(contentLen)
do {
val currentRead = channel.readAvailable(data, offset, byteBufferSize)
val progress = if(contentLen == 0) 0 else ( offset / contentLen.toDouble() ) * 100
logger?.d { "progress: $progress" }
offset += currentRead
} while (currentRead >= 0)
}
有两件事不能用这个解决方案。 1.) 我处于 HttpClient 的上下文中,因此这就是我访问 get() 的方式。 2.) 我正在创建一个字节缓冲区大小1024 * 100
为了不让readAvailable
方法块太长,尽管这可能没有必要......它的一个好处是它决定了您发布进度更新的频率。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)