Comprehensive set of read and write operations for primitive types, byte arrays, and text content. These extension functions provide the essential functionality for actual data transfer through channels.
Read primitive data types from a ByteReadChannel.
/** Read a single byte */
suspend fun ByteReadChannel.readByte(): Byte
/** Read a short (2 bytes) */
suspend fun ByteReadChannel.readShort(): Short
/** Read an integer (4 bytes) */
suspend fun ByteReadChannel.readInt(): Int
/** Read a float (4 bytes) */
suspend fun ByteReadChannel.readFloat(): Float
/** Read a long (8 bytes) */
suspend fun ByteReadChannel.readLong(): Long
/** Read a double (8 bytes) */
suspend fun ByteReadChannel.readDouble(): DoubleUsage Examples:
import io.ktor.utils.io.*
suspend fun readPrimitivesExample() {
val channel = ByteReadChannel(byteArrayOf(0x42, 0x00, 0x00, 0x00, 0x7B))
val byte = channel.readByte() // 0x42
val int = channel.readInt() // 0x0000007B
}Read byte arrays and buffers from channels.
/** Read exactly count bytes into a new ByteArray */
suspend fun ByteReadChannel.readByteArray(count: Int): ByteArray
/** Read available bytes into a Buffer */
suspend fun ByteReadChannel.readBuffer(): Buffer
/** Read up to max bytes into a Buffer */
suspend fun ByteReadChannel.readBuffer(max: Int): Buffer
/** Read all remaining bytes into a ByteArray */
suspend fun ByteReadChannel.toByteArray(): ByteArray
/** Read available bytes into a byte array buffer */
suspend fun ByteReadChannel.readAvailable(
buffer: ByteArray,
offset: Int = 0,
length: Int = buffer.size - offset
): IntUsage Examples:
import io.ktor.utils.io.*
suspend fun readArraysExample() {
val channel = ByteReadChannel("Hello World!")
// Read first 5 bytes
val first5 = channel.readByteArray(5)
println(String(first5)) // "Hello"
// Read all remaining bytes
val remaining = channel.toByteArray()
println(String(remaining)) // " World!"
}Read text content with various encoding and line-ending options.
/** Read a UTF-8 line, returning null if EOF reached */
suspend fun ByteReadChannel.readUTF8Line(max: Int = Int.MAX_VALUE): String?
/** Read a UTF-8 line into an Appendable, returns true if line was read */
suspend fun ByteReadChannel.readUTF8LineTo(
out: Appendable,
max: Int = Int.MAX_VALUE
): Boolean
/** Read a UTF-8 line with specific line ending mode */
suspend fun ByteReadChannel.readUTF8LineTo(
out: Appendable,
max: Int,
lineEnding: LineEndingMode
): BooleanUsage Examples:
import io.ktor.utils.io.*
suspend fun readTextExample() {
val channel = ByteReadChannel("Line 1\nLine 2\nLine 3")
// Read lines one by one
while (!channel.isClosedForRead) {
val line = channel.readUTF8Line()
if (line != null) {
println("Read line: $line")
} else {
break
}
}
}Advanced reading operations for pattern matching and data manipulation.
/** Copy all data from this channel to the destination channel */
suspend fun ByteReadChannel.copyTo(channel: ByteWriteChannel): Long
/** Copy up to limit bytes to the destination channel */
suspend fun ByteReadChannel.copyTo(channel: ByteWriteChannel, limit: Long): Long
/** Copy all data and close the destination channel */
suspend fun ByteReadChannel.copyAndClose(channel: ByteWriteChannel): Long
/** Check if the channel is exhausted (no more data available) */
suspend fun ByteReadChannel.exhausted(): Boolean
/** Discard up to max bytes, returning actual bytes discarded */
suspend fun ByteReadChannel.discard(max: Long = Long.MAX_VALUE): Long
/** Discard exactly the specified number of bytes */
suspend fun ByteReadChannel.discardExact(value: Long)
/** Peek at the next count bytes without consuming them */
suspend fun ByteReadChannel.peek(count: Int): ByteString?
/** Skip bytes if they match the given ByteString */
suspend fun ByteReadChannel.skipIfFound(byteString: ByteString): BooleanUsage Examples:
import io.ktor.utils.io.*
import kotlinx.io.*
suspend fun advancedReadExample() {
val source = ByteReadChannel("Hello World! This is a test.")
val destination = ByteChannel()
// Copy first 12 bytes
val copied = source.copyTo(destination, limit = 12)
println("Copied $copied bytes")
// Check what remains
val remaining = source.toByteArray()
println("Remaining: ${String(remaining)}")
// Peek at destination content
val peeked = destination.peek(5)
println("Peeked: ${peeked?.decodeToString()}")
}Write primitive data types to a ByteWriteChannel.
/** Write a single byte */
suspend fun ByteWriteChannel.writeByte(value: Byte)
/** Write a short (2 bytes) */
suspend fun ByteWriteChannel.writeShort(value: Short)
/** Write an integer (4 bytes) */
suspend fun ByteWriteChannel.writeInt(value: Int)
/** Write a float (4 bytes) */
suspend fun ByteWriteChannel.writeFloat(value: Float)
/** Write a long (8 bytes) */
suspend fun ByteWriteChannel.writeLong(value: Long)
/** Write a double (8 bytes) */
suspend fun ByteWriteChannel.writeDouble(value: Double)Usage Examples:
import io.ktor.utils.io.*
suspend fun writePrimitivesExample() {
val channel = ByteChannel()
channel.writeByte(0x42)
channel.writeInt(123)
channel.writeLong(456789L)
channel.writeFloat(3.14f)
channel.writeDouble(2.718281828)
channel.flushAndClose()
}Write byte arrays and data sources to channels.
/** Write the entire byte array */
suspend fun ByteWriteChannel.writeByteArray(array: ByteArray)
/** Write a portion of a byte array */
suspend fun ByteWriteChannel.writeFully(
value: ByteArray,
startIndex: Int,
endIndex: Int
)
/** Write data from a Source */
suspend fun ByteWriteChannel.writeSource(source: Source)
/** Write data from a packet Source */
suspend fun ByteWriteChannel.writePacket(source: Source)Usage Examples:
import io.ktor.utils.io.*
import kotlinx.io.*
suspend fun writeArraysExample() {
val channel = ByteChannel()
// Write byte array
val data = "Hello".toByteArray()
channel.writeByteArray(data)
// Write partial array
val moreData = " World!".toByteArray()
channel.writeFully(moreData, 0, 6) // Write " World"
// Write from Source
val buffer = Buffer()
buffer.writeUtf8("!")
channel.writeSource(buffer)
channel.flushAndClose()
}Write text content with encoding support.
/** Write a string using the platform default encoding */
suspend fun ByteWriteChannel.writeString(value: String)
/** Write a string using UTF-8 encoding */
suspend fun ByteWriteChannel.writeStringUtf8(value: String)Usage Examples:
import io.ktor.utils.io.*
suspend fun writeTextExample() {
val channel = ByteChannel()
channel.writeStringUtf8("Hello, ")
channel.writeStringUtf8("World!")
channel.writeStringUtf8("\n")
channel.flushAndClose()
// Read back the result
val result = channel.toByteArray()
println(String(result)) // "Hello, World!\n"
}Advanced writing operations for custom data handling.
/**
* Request space for writing and execute a block with the available buffer
* Returns the number of bytes actually written
*/
suspend fun ByteWriteChannel.write(
desiredSpace: Int,
block: (ByteArray, Int, Int) -> Int
): Int
/** Wait until there is free space available for writing */
suspend fun ByteWriteChannel.awaitFreeSpace()Usage Examples:
import io.ktor.utils.io.*
suspend fun advancedWriteExample() {
val channel = ByteChannel()
// Custom write operation
val bytesWritten = channel.write(1024) { buffer, offset, length ->
// Custom logic to fill the buffer
val data = "Custom data".toByteArray()
val copyLength = minOf(data.size, length)
data.copyInto(buffer, offset, 0, copyLength)
copyLength
}
println("Wrote $bytesWritten bytes")
channel.flushAndClose()
}Integration with coroutines for producer/consumer patterns.
/** Create a reader coroutine */
fun CoroutineScope.reader(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend ByteWriteChannel.() -> Unit
): ReaderJob
/** Create a writer coroutine */
fun CoroutineScope.writer(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend ByteWriteChannel.() -> Unit
): WriterJobUsage Examples:
import io.ktor.utils.io.*
import kotlinx.coroutines.*
suspend fun coroutineBuilderExample() {
val scope = CoroutineScope(Dispatchers.IO)
// Create a reader
val readerJob = scope.reader {
writeStringUtf8("Data from reader")
flushAndClose()
}
// Read from the channel
val channel = readerJob.channel
val data = channel.toByteArray()
println(String(data))
readerJob.join()
}interface ReaderJob : Job {
val channel: ByteReadChannel
}
interface WriterJob : Job {
val channel: ByteWriteChannel
}