如何使用 Ktor 客户端将响应正文流式传输到 Android 和 iOS 上的 KMP 中的文件?
可以将以下预期功能添加到公共代码中,该功能将数据写入从
ByteReadChannel
读取的文件中:
expect suspend fun ByteReadChannel.writeToFile(filepath: String)
以下是上述函数用法的示例:
val client = HttpClient()
client.prepareGet("https://httpbin.org/image/jpeg").execute {
it.bodyAsChannel().writeToFile("/path/to/file")
}
对于 JVM 和 Android,
File.writeChannel
可用于将 ByteReadChannel
流式传输到文件:
actual suspend fun ByteReadChannel.writeToFile(filepath: String) {
this.copyTo(File(filepath).writeChannel())
}
对于 iOS,dispatch_write 函数可用于在从
ByteReadChannel
读取块的同时异步写入文件:
private const val BUFFER_SIZE = 4096
@OptIn(ExperimentalForeignApi::class)
actual suspend fun ByteReadChannel.writeToFile(filepath: String) {
val channel = this
val queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.convert(), 0u)
memScoped {
val dst = allocArray<ByteVar>(BUFFER_SIZE)
val fd = open(filepath, O_RDWR)
try {
while (!channel.isClosedForRead) {
val rs = channel.readAvailable(dst, 0, BUFFER_SIZE)
if (rs < 0) break
val data = dispatch_data_create(dst, rs.convert(), queue) {}
dispatch_write(fd, data, queue) { _, error ->
if (error != 0) {
channel.cancel(IllegalStateException("Unable to write data to the file $filepath"))
}
}
}
} finally {
close(fd)
}
}
}