Skip to content

Okio

Developer UtilitiesUtilities/IOKotlin

What it is

Okio is a library for I/O in Kotlin and Java, offering buffered sources and sinks, a multiplatform filesystem abstraction and efficient byte handling.

Source reads, Sink writes, and Buffer holds bytes efficiently. FileSystem provides a testable, multiplatform filesystem API.

Installation

implementation("com.squareup.okio:okio:3.9.0")

Getting started

The smallest useful thing you can do with it, and what each part means.

Reading and writing
val path = "books.json".toPath()

FileSystem.SYSTEM.write(path) {
    writeUtf8(json)
}

val text = FileSystem.SYSTEM.read(path) {
    readUtf8()
}

// Streaming line by line — constant memory on a huge file.
FileSystem.SYSTEM.source(path).buffer().use { source ->
    while (true) {
        val line = source.readUtf8Line() ?: break
        process(line)
    }
}
The read and write lambdas close the resource automatically, which removes the try-with-resources ceremony that java.io requires.

Advanced usage

Where the library earns its place over a simpler alternative.

In-memory filesystem for tests, and hashing
// A real FileSystem implementation with no disk — tests run fast
// and cannot leave files behind.
val fs = FakeFileSystem()
fs.write("config.json".toPath()) { writeUtf8("""{"port":8080}""") }

val service = ConfigService(fs)   // inject the filesystem
assertEquals(8080, service.load().port)
fs.checkNoOpenFiles()             // asserts nothing leaked

// Hash while streaming, without buffering the whole file.
val sha = FileSystem.SYSTEM.source(path).buffer().use { it.readByteString().sha256() }

// ByteString is immutable and cheap to compare and encode.
val token = "secret".encodeUtf8().sha256().hex()
FakeFileSystem is the strongest reason to depend on Okio directly: injecting a FileSystem makes file-touching code unit-testable without temporary directories.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

FileNotFoundException on a path that exists
Okio paths are platform-aware. Build them with toPath() and resolve() rather than concatenating strings.
Data is missing after writing
The sink was not closed or flushed. Use the write { } lambda, which handles both.

Best practices

  • Inject FileSystem rather than using java.io directly, so tests can substitute FakeFileSystem.
  • Use .buffer() on sources and sinks; unbuffered I/O is much slower.
  • Use ByteString for immutable byte data — it is safe to share and cheap to compare.
  • Call checkNoOpenFiles() in tests to catch leaked handles.

Background

Why it exists, and what it was reacting to.

Built by Square as OkHttp's foundation, Okio exists because java.io's streams are awkward and allocate heavily. Its ByteString and Buffer types move data with far less copying.