A modern I/O library for Android, Java, and Kotlin Multiplatform
npx @tessl/cli install tessl/maven-com-squareup-okio--okio@3.12.0Okio is a modern I/O library for Android, Java, and Kotlin Multiplatform that complements java.io and java.nio to make accessing, storing, and processing data much easier. Originally developed as a component of OkHttp, it provides efficient buffered I/O operations, file system abstractions, and cross-platform compatibility.
build.gradle.kts dependencies: implementation("com.squareup.okio:okio:3.12.0")import okio.*
// Or specific imports:
import okio.ByteString
import okio.Buffer
import okio.FileSystem
import okio.Pathimport okio.*
// Working with byte strings
val data = "Hello, Okio!".encodeUtf8()
println(data.base64()) // SGVsbG8sIE9raW8h
println(data.sha256().hex()) // Hash as hex string
// Buffered I/O operations
val buffer = Buffer()
buffer.writeUtf8("Hello, ")
buffer.writeUtf8("world!")
println(buffer.readUtf8()) // Hello, world!
// File system operations
val path = "/tmp/example.txt".toPath()
FileSystem.SYSTEM.write(path) {
writeUtf8("File content here")
}
val content = FileSystem.SYSTEM.read(path) {
readUtf8()
}Okio is built around several key abstractions:
The library uses efficient internal segment-based buffering and provides both low-level streaming APIs and high-level convenience methods.
Essential byte manipulation, buffered I/O, and streaming operations.
// ByteString - immutable byte sequences
expect open class ByteString : Comparable<ByteString> {
val size: Int
fun utf8(): String
fun base64(): String
fun base64Url(): String
fun hex(): String
fun md5(): ByteString
fun sha1(): ByteString
fun sha256(): ByteString
fun sha512(): ByteString
fun hmacSha1(key: ByteString): ByteString
fun hmacSha256(key: ByteString): ByteString
fun hmacSha512(key: ByteString): ByteString
fun toAsciiLowercase(): ByteString
fun toAsciiUppercase(): ByteString
fun substring(beginIndex: Int = 0, endIndex: Int = size): ByteString
fun toByteArray(): ByteArray
operator fun get(index: Int): Byte
fun startsWith(prefix: ByteString): Boolean
fun endsWith(suffix: ByteString): Boolean
fun indexOf(other: ByteString, fromIndex: Int = 0): Int
fun rangeEquals(offset: Int, other: ByteString, otherOffset: Int = 0, byteCount: Int): Boolean
companion object {
val EMPTY: ByteString
fun of(vararg data: Byte): ByteString
}
}
// Buffer - mutable byte collections
expect class Buffer : BufferedSource, BufferedSink {
var size: Long
fun copyTo(out: Buffer, offset: Long = 0L, byteCount: Long): Buffer
fun copyTo(out: Buffer, offset: Long = 0L): Buffer
fun completeSegmentByteCount(): Long
operator fun get(pos: Long): Byte
fun clear()
fun skip(byteCount: Long)
fun snapshot(): ByteString
fun snapshot(byteCount: Int): ByteString
fun copy(): Buffer
fun md5(): ByteString
fun sha1(): ByteString
fun sha256(): ByteString
fun sha512(): ByteString
fun hmacSha1(key: ByteString): ByteString
fun hmacSha256(key: ByteString): ByteString
fun hmacSha512(key: ByteString): ByteString
}
// BufferedSource - efficient reading interface
expect sealed interface BufferedSource : Source {
val buffer: Buffer
fun exhausted(): Boolean
fun require(byteCount: Long)
fun request(byteCount: Long): Boolean
fun readByte(): Byte
fun readShort(): Short
fun readShortLe(): Short
fun readInt(): Int
fun readIntLe(): Int
fun readLong(): Long
fun readLongLe(): Long
fun readDecimalLong(): Long
fun readHexadecimalUnsignedLong(): Long
fun readUtf8(): String
fun readUtf8(byteCount: Long): String
fun readUtf8Line(): String?
fun readUtf8LineStrict(): String
fun readUtf8CodePoint(): Int
fun readByteString(): ByteString
fun readByteString(byteCount: Long): ByteString
fun readByteArray(): ByteArray
fun readByteArray(byteCount: Long): ByteArray
fun read(sink: ByteArray): Int
fun readFully(sink: ByteArray)
fun readFully(sink: Buffer, byteCount: Long)
fun readAll(sink: Sink): Long
fun skip(byteCount: Long)
fun indexOf(b: Byte): Long
fun indexOf(bytes: ByteString): Long
fun indexOfElement(targetBytes: ByteString): Long
fun rangeEquals(offset: Long, bytes: ByteString): Boolean
fun peek(): BufferedSource
fun select(options: Options): Int
fun <T : Any> select(options: TypedOptions<T>): T?
}
// BufferedSink - efficient writing interface
expect sealed interface BufferedSink : Sink {
val buffer: Buffer
fun write(byteString: ByteString): BufferedSink
fun write(byteString: ByteString, offset: Int, byteCount: Int): BufferedSink
fun write(source: ByteArray): BufferedSink
fun write(source: ByteArray, offset: Int, byteCount: Int): BufferedSink
fun writeAll(source: Source): Long
fun write(source: Source, byteCount: Long): BufferedSink
fun writeUtf8(string: String): BufferedSink
fun writeUtf8(string: String, beginIndex: Int, endIndex: Int): BufferedSink
fun writeUtf8CodePoint(codePoint: Int): BufferedSink
fun writeByte(b: Int): BufferedSink
fun writeShort(s: Int): BufferedSink
fun writeShortLe(s: Int): BufferedSink
fun writeInt(i: Int): BufferedSink
fun writeIntLe(i: Int): BufferedSink
fun writeLong(v: Long): BufferedSink
fun writeLongLe(v: Long): BufferedSink
fun writeDecimalLong(v: Long): BufferedSink
fun writeHexadecimalUnsignedLong(v: Long): BufferedSink
override fun flush()
fun emit(): BufferedSink
fun emitCompleteSegments(): BufferedSink
}// String extensions for ByteString creation
fun String.encodeUtf8(): ByteString
fun String.decodeBase64(): ByteString?
fun String.decodeHex(): ByteString
// ByteArray extensions
fun ByteArray.toByteString(offset: Int = 0, byteCount: Int = size): ByteString
// Source/Sink buffering utilities
fun Source.buffer(): BufferedSource
fun Sink.buffer(): BufferedSink
fun blackholeSink(): Sink
// Resource management
inline fun <T : Closeable?, R> T.use(block: (T) -> R): RCross-platform file system access with path manipulation and metadata handling.
// Path - hierarchical file system addresses
expect class Path {
val root: Path?
val segments: List<String>
val isAbsolute: Boolean
val isRelative: Boolean
val volumeLetter: Char?
val name: String
val parent: Path?
val isRoot: Boolean
operator fun div(child: String): Path
operator fun div(child: ByteString): Path
operator fun div(child: Path): Path
fun resolve(child: String, normalize: Boolean = false): Path
fun resolve(child: ByteString, normalize: Boolean = false): Path
fun resolve(child: Path, normalize: Boolean = false): Path
fun relativeTo(other: Path): Path
fun normalized(): Path
companion object {
val DIRECTORY_SEPARATOR: String
}
}
// FileSystem - file and directory operations
expect abstract class FileSystem {
abstract fun canonicalize(path: Path): Path
fun metadata(path: Path): FileMetadata
abstract fun metadataOrNull(path: Path): FileMetadata?
fun exists(path: Path): Boolean
abstract fun list(dir: Path): List<Path>
abstract fun listOrNull(dir: Path): List<Path>?
open fun listRecursively(dir: Path, followSymlinks: Boolean = false): Sequence<Path>
abstract fun openReadOnly(file: Path): FileHandle
abstract fun openReadWrite(file: Path, mustCreate: Boolean = false, mustExist: Boolean = false): FileHandle
abstract fun source(file: Path): Source
inline fun <T> read(file: Path, readerAction: BufferedSource.() -> T): T
abstract fun sink(file: Path, mustCreate: Boolean = false): Sink
inline fun <T> write(file: Path, mustCreate: Boolean = false, writerAction: BufferedSink.() -> T): T
abstract fun appendingSink(file: Path, mustExist: Boolean = false): Sink
abstract fun createDirectory(dir: Path, mustCreate: Boolean = false)
fun createDirectories(dir: Path, mustCreate: Boolean = false)
abstract fun atomicMove(source: Path, target: Path)
open fun copy(source: Path, target: Path)
abstract fun delete(path: Path, mustExist: Boolean = false)
open fun deleteRecursively(fileOrDirectory: Path, mustExist: Boolean = false)
abstract fun createSymlink(source: Path, target: Path)
companion object {
val SYSTEM: FileSystem
val SYSTEM_TEMPORARY_DIRECTORY: Path
}
}
// FileHandle - random access file I/O
abstract class FileHandle : Closeable {
val readWrite: Boolean
fun read(fileOffset: Long, array: ByteArray, arrayOffset: Int = 0, byteCount: Int = array.size): Int
fun read(fileOffset: Long, sink: Buffer, byteCount: Long): Long
fun write(fileOffset: Long, array: ByteArray, arrayOffset: Int = 0, byteCount: Int = array.size)
fun write(fileOffset: Long, source: Buffer, byteCount: Long)
fun size(): Long
fun resize(size: Long)
fun flush()
fun source(fileOffset: Long = 0L): Source
fun sink(fileOffset: Long = 0L): Sink
fun appendingSink(): Sink
fun position(source: Source): Long
fun reposition(source: Source, position: Long)
fun position(sink: Sink): Long
fun reposition(sink: Sink, position: Long)
override fun close()
}// String to Path conversion
fun String.toPath(normalize: Boolean = false): Path
// FileSystem convenience extensions
inline fun <T> FileSystem.read(file: Path, readerAction: BufferedSource.() -> T): T
inline fun <T> FileSystem.write(file: Path, mustCreate: Boolean = false, writerAction: BufferedSink.() -> T): T
// UTF-8 utilities
fun String.utf8Size(beginIndex: Int = 0, endIndex: Int = length): LongData compression using GZIP and deflate algorithms with native zlib integration.
// GZIP compression
class GzipSink(sink: Sink) : Sink {
val deflater: Deflater
}
fun Sink.gzip(): GzipSink
// Deflate compression (native implementation)
actual class Deflater {
constructor()
constructor(level: Int, nowrap: Boolean)
var flush: Int
fun getBytesRead(): Long
fun end()
}
// ZIP file system access
class ZipFileSystem(zipPath: Path, fileSystem: FileSystem) : FileSystemCryptographic hashing operations and secure data handling.
// Hashing sources and sinks
expect class HashingSource(source: Source, digest: Digest) : Source {
val hash: ByteString
}
expect class HashingSink(sink: Sink, digest: Digest) : Sink {
val hash: ByteString
}Built-in hash functions available on ByteString and Buffer:
md5(): ByteStringsha1(): ByteStringsha256(): ByteStringsha512(): ByteStringhmacSha1(), hmacSha256(), hmacSha512()Helper functions, timeout management, and advanced buffer operations.
// Timeout management
expect open class Timeout {
companion object {
val NONE: Timeout
}
}
// Selection and matching
class Options private constructor() : List<ByteString> {
companion object {
fun of(vararg byteStrings: ByteString): Options
}
}
class TypedOptions<T : Any> private constructor() : List<T> {
companion object {
inline fun <T : Any> of(values: Iterable<T>, encode: (T) -> ByteString): TypedOptions<T>
}
}// BufferedSource selection operations
fun BufferedSource.select(options: Options): Int
fun <T : Any> BufferedSource.select(options: TypedOptions<T>): T?
// Advanced buffer operations (UnsafeCursor for high-performance access)
class Buffer.UnsafeCursor {
var buffer: Buffer?
var readWrite: Boolean
var offset: Long
var data: ByteArray?
var start: Int
var end: Int
fun next(): Int
fun seek(offset: Long): Int
}Additional functionality specific to Apple platforms:
// Foundation integration
fun NSData.toByteString(): ByteStringOkio uses standard Kotlin/platform exception types:
expect open class IOException : Exception
expect class FileNotFoundException : IOException
expect class EOFException : IOException
expect class ProtocolException : IOExceptionCommon error scenarios:
// Core interfaces
interface Source : Closeable {
fun read(sink: Buffer, byteCount: Long): Long
fun timeout(): Timeout
}
interface Sink : Closeable {
fun write(source: Buffer, byteCount: Long)
fun flush()
fun timeout(): Timeout
}
interface Closeable {
fun close()
}
// File metadata
class FileMetadata(
val isRegularFile: Boolean = false,
val isDirectory: Boolean = false,
val symlinkTarget: Path? = null,
val size: Long? = null,
val createdAtMillis: Long? = null,
val lastModifiedAtMillis: Long? = null,
val lastAccessedAtMillis: Long? = null,
val extras: Map<KClass<*>, Any> = emptyMap()
)
// Platform synchronization
expect class Lock() {
inline fun <T> withLock(action: () -> T): T
}