Skip to content

I/Oの相互運用性

Ktorは、基本的なI/Oプリミティブを提供するマルチプラットフォームKotlinライブラリであるkotlinx-ioをベースに構築された、ノンブロッキングで非同期なI/Oをサポートしています。これにより、HTTPリクエストとレスポンスのボディをストリーミングしたり、ファイルを読み書きしたり、データをメモリにすべてロードすることなくインクリメンタルに処理したりすることができます。

異なるI/Oモデルを使用する外部ライブラリやプラットフォームを扱う場合は、一連のアダプターを使用して以下と相互運用できます。

  • RawSourceRawSinkなどのkotlinx-ioの型
  • OutputStreamなどのJava I/O型

このページでは、KtorのI/Oプリミティブ(ByteReadChannelByteWriteChannel)とこれらの外部の型との間で変換を行う方法について説明します。

ByteReadChannelからRawSourceへの変換

ByteReadChannelRawSourceに変換するには、.asSource()拡張関数を使用します。

kotlin
client.prepareGet("https://httpbin.org/bytes/1024").execute { httpResponse ->
    val channel: ByteReadChannel = httpResponse.body()
    val source: RawSource = channel.asSource()
    val buffered = source.buffered()
    val firstByte = buffered.readByte()
    println("Read first byte from RawSource: $firstByte")
}

ByteWriteChannelからRawSinkへの変換

中断(suspending)ByteWriteChannelRawSinkに変換するには、.asSink()拡張関数を使用します。

kotlin
get("/sink") {
    call.respondBytesWriter {
        val sink: RawSink = this.asSink()
        sink.buffered().use { buffered ->
            buffered.writeString("Hello from kotlinx-io Sink!")
        }
    }
}

このアダプターによって生成されたRawSinkは、データのフラッシュ時に内部でrunBlockingを使用するため、フラッシュ操作が呼び出し元のスレッドをブロックする可能性があります。

RawSinkからByteWriteChannelへの変換

RawSinkを中断ByteWriteChannelとしてラップするには、.asByteWriteChannel()拡張関数を使用します。

kotlin
get("/raw-sink") {
    val buffer = Buffer()
    val channel = buffer.asByteWriteChannel()
    channel.writeByte(42)
    channel.writeFully("Hello via RawSink".toByteArray())
    channel.flushAndClose()
    call.respondBytes(buffer.readByteArray())
}

これにより、中断関数からシンクへの非同期書き込みが可能になります。返されるチャネルはバッファリングされます。すべてのデータが書き込まれたことを確実にするには、.flush()または.flushAndClose()を使用してください。

OutputStreamからByteWriteChannelへの変換

JavaのOutputStreamByteWriteChannelに変換するには、.asByteWriteChannel()拡張関数を使用します。

kotlin
get("/output-stream") {
    val out = ByteArrayOutputStream()
    val channel = out.asByteWriteChannel()
    channel.writeFully("Hello from OutputStream-backed channel!".toByteArray())
    channel.flushAndClose()
    call.respondBytes(out.toByteArray())
}

ByteWriteChannelでのすべての操作はバッファリングされます。基盤となるOutputStreamは、ByteWriteChannel.flush()が呼び出されたときにのみデータを受け取ります。