Okio is a library that complements java.io and java.nio to make it much easier to access, store, and process your data. It started as a component of OkHttp, the capable HTTP client included in Android. It’s well-exercised and ready to solve new problems.


ByteStrings and Buffers


Okio is built around two types that pack a lot of capability into a straightforward API:


  • ByteString is an immutable sequence of bytes. For character data, String is fundamental. ByteString is String’s long-lost brother, making it easy to treat binary data as a value. This class is ergonomic: it knows how to encode and decode itself as hex, base64, and UTF-8.
  • Buffer is a mutable sequence of bytes. Like ArrayList, you don’t need to size your buffer in advance. You read and write buffers as a queue: write data to the end and read it from the front. There’s no obligation to manage positions, limits, or capacities.
  • ByteString是一个不可改变的字节序列。对于字符数据,String是基本的。ByteString是String失散多年的兄弟,使其很容易将二进制数据当作一个值。这个类是符合人体工程学的:它知道如何将自己编码和解码为十六进制、base64和UTF-8。
  • Buffer是一个可变的字节序列。像ArrayList一样,你不需要事先确定缓冲区的大小。你以队列的方式读写缓冲区:把数据写到最后,然后从前面读取。没有义务去管理位置、限制或容量。

Internally, ByteString and Buffer do some clever things to save CPU and memory. If you encode a UTF-8 string as a ByteString, it caches a reference to that string so that if you decode it later, there’s no work to do.



Buffer is implemented as a linked list of segments. When you move data from one buffer to another, it reassigns ownership of the segments rather than copying the data across. This approach is particularly helpful for multithreaded programs: a thread that talks to the network can exchange data with a worker thread without any copying or ceremony.


Sources and Sinks


An elegant part of the java.io design is how streams can be layered for transformations like encryption and compression. Okio includes its own stream types called Source and Sink that work like InputStream and OutputStream, but with some key differences:


  • Timeouts. The streams provide access to the timeouts of the underlying I/O mechanism. Unlike the java.io socket streams, both read() and write() calls honor timeouts.
  • Easy to implement. Source declares three methods: read(), close(), and timeout(). There are no hazards like available() or single-byte reads that cause correctness and performance surprises.
  • Easy to use. Although implementations of Source and Sink have only three methods to write, callers are given a rich API with the BufferedSource and BufferedSink interfaces. These interfaces give you everything you need in one place.
  • No artificial distinction between byte streams and char streams. It’s all data. Read and write it as bytes, UTF-8 strings, big-endian 32-bit integers, little-endian shorts; whatever you want. No more InputStreamReader!
  • Easy to test. The Buffer class implements both BufferedSource and BufferedSink so your test code is simple and clear.
  • 超时。流提供了对底层I/O机制的超时的访问。与java.io套接字流不同的是,read()和write()的调用都遵守超时。
  • 易于实现。Source声明了三个方法:read(), close(), 和timeout()。没有像available()或单字节读取这样的危险,导致正确性和性能的意外。
  • 易于使用。尽管Source和Sink的实现只有三个方法可以写,但调用者可以通过BufferedSource和BufferedSink接口获得丰富的API。这些接口在一个地方给你提供了你所需要的一切。
  • 字节流和字符流之间没有人为的区分。这都是数据。以字节、UTF-8字符串、big-endian 32位整数、little-endian shorts的形式读写;任何你想要的。不再有InputStreamReader!
  • 易于测试。Buffer类同时实现了BufferedSource和BufferedSink,所以你的测试代码简单而清晰。

Sources and sinks interoperate with InputStream and OutputStream. You can view any Source as an InputStream, and you can view any InputStream as a Source. Similarly for Sink and OutputStream.

Source声明了三个方法:read(), close(), 和timeout()。没有像available()或单字节读取这样的危险,导致正确性和性能的意外。 易于使用。尽管SourceSink的实现只有三个方法可以写,但调用者可以通过BufferedSourceBufferedSink接口获得丰富的API。这些接口在一个地方给你提供了你所需要的一切。


A Few “Ok” Libraries (slides): An introduction to Okio and three libraries written with it.

Decoding the Secrets of Binary Data (slides): How data encoding works and how Okio does it.

Ok Multiplatform! (slides): How we changed Okio’s implementation language from Java to Kotlin.