Aleksei Tirman [JB]
02/27/2025, 11:33 AMursus
02/27/2025, 11:36 AMbodyAsChannel
to download a file?ursus
02/27/2025, 11:38 AMByteReadChannel
https://api.ktor.io/ktor-client/ktor-client-core/io.ktor.client.statement/body-as-channel.htmlAleksei Tirman [JB]
02/27/2025, 11:41 AMByteReadChannel
to save a response body to a file:
client.get("<https://example.com>").bodyAsChannel()
.copyTo(File("/path/to/file").writeChannel())
ursus
02/27/2025, 11:42 AM.use { .. }
?Aleksei Tirman [JB]
02/27/2025, 11:44 AMursus
02/27/2025, 11:44 AMursus
02/27/2025, 11:45 AMAleksei Tirman [JB]
02/27/2025, 11:45 AMcopyAndClose
instead of copyTo
to close the ByteWriteChannel
associated with the file.ursus
02/27/2025, 11:46 AMursus
02/27/2025, 11:47 AMSource
? I read that is sort of the InputStream
of the kotlinx.io? Isn't the channel an unnecessary abstraction?Aleksei Tirman [JB]
02/27/2025, 4:50 PMwhat if it throws midway?Then the channel will be closed.
Aleksei Tirman [JB]
02/27/2025, 4:53 PMByteReadChannel
unlike the Source
provides suspendable read operations.ursus
02/27/2025, 5:54 PM@OptIn(InternalAPI::class)
public suspend fun ByteReadChannel.copyAndClose(channel: ByteWriteChannel): Long {
var result = 0L
try {
while (!isClosedForRead) {
result += readBuffer.transferTo(channel.writeBuffer)
channel.flush()
awaitContent()
}
closedCause?.let { throw it }
} catch (cause: Throwable) {
cancel(cause)
channel.close(cause)
throw cause
} finally {
channel.flushAndClose()
}
return result
}
Aleksei Tirman [JB]
02/28/2025, 8:52 AMcancel(cause)
call in the beginning of the catch block.