Okio ==== Okio is a new library that complements `java.io` and `java.nio` to make it much easier to access, store, and process your data. ByteStrings and Buffers ----------------------- Okio is built around two types that pack a lot of capability into a straightforward API: * [**ByteString**][3] 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**][4] 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. 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`][5] and [`Sink`][6] 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`][7] and [`BufferedSink`][8] 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. 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`. Dependable ---------- Okio started as a component of [OkHttp][1], the capable HTTP+SPDY client included in Android. It's well-exercised and ready to solve new problems. Example: a PNG decoder ---------------------- Decoding the chunks of a PNG file demonstrates Okio in practice. ```java private static final ByteString PNG_HEADER = ByteString.decodeHex("89504e470d0a1a0a"); public void decodePng(InputStream in) throws IOException { BufferedSource pngSource = Okio.buffer(Okio.source(in)); ByteString header = pngSource.readByteString(PNG_HEADER.size()); if (!header.equals(PNG_HEADER)) { throw new IOException("Not a PNG."); } while (true) { Buffer chunk = new Buffer(); // Each chunk is a length, type, data, and CRC offset. int length = pngSource.readInt(); String type = pngSource.readUtf8(4); pngSource.readFully(chunk, length); int crc = pngSource.readInt(); decodeChunk(type, chunk); if (type.equals("IEND")) break; } pngSource.close(); } private void decodeChunk(String type, Buffer chunk) { if (type.equals("IHDR")) { int width = chunk.readInt(); int height = chunk.readInt(); System.out.printf("%08x: %s %d x %d%n", chunk.size(), type, width, height); } else { System.out.printf("%08x: %s%n", chunk.size(), type); } } ``` Download -------- Download [the latest JAR][2] or grab via Maven: ```xml <dependency> <groupId>com.squareup.okio</groupId> <artifactId>okio</artifactId> <version>1.6.0</version> </dependency> ``` or Gradle: ```groovy compile 'com.squareup.okio:okio:1.6.0' ``` Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. [1]: https://github.com/square/okhttp [2]: https://search.maven.org/remote_content?g=com.squareup.okio&a=okio&v=LATEST [3]: http://square.github.io/okio/okio/ByteString.html [4]: http://square.github.io/okio/okio/Buffer.html [5]: http://square.github.io/okio/okio/Source.html [6]: http://square.github.io/okio/okio/Sink.html [7]: http://square.github.io/okio/okio/BufferedSource.html [8]: http://square.github.io/okio/okio/BufferedSink.html [snap]: https://oss.sonatype.org/content/repositories/snapshots/