1 Okio 2 ==== 3 4 Okio is a new library that complements `java.io` and `java.nio` to make it much 5 easier to access, store, and process your data. 6 7 ByteStrings and Buffers 8 ----------------------- 9 10 Okio is built around two types that pack a lot of capability into a 11 straightforward API: 12 13 * [**ByteString**][3] is an immutable sequence of bytes. For character data, `String` 14 is fundamental. `ByteString` is String's long-lost brother, making it easy to 15 treat binary data as a value. This class is ergonomic: it knows how to encode 16 and decode itself as hex, base64, and UTF-8. 17 18 * [**Buffer**][4] is a mutable sequence of bytes. Like `ArrayList`, you don't need 19 to size your buffer in advance. You read and write buffers as a queue: write 20 data to the end and read it from the front. There's no obligation to manage 21 positions, limits, or capacities. 22 23 Internally, `ByteString` and `Buffer` do some clever things to save CPU and 24 memory. If you encode a UTF-8 string as a `ByteString`, it caches a reference to 25 that string so that if you decode it later, there's no work to do. 26 27 `Buffer` is implemented as a linked list of segments. When you move data from 28 one buffer to another, it _reassigns ownership_ of the segments rather than 29 copying the data across. This approach is particularly helpful for multithreaded 30 programs: a thread that talks to the network can exchange data with a worker 31 thread without any copying or ceremony. 32 33 Sources and Sinks 34 ----------------- 35 36 An elegant part of the `java.io` design is how streams can be layered for 37 transformations like encryption and compression. Okio includes its own stream 38 types called [`Source`][5] and [`Sink`][6] that work like `InputStream` and 39 `OutputStream`, but with some key differences: 40 41 * **Timeouts.** The streams provide access to the timeouts of the underlying 42 I/O mechanism. Unlike the `java.io` socket streams, both `read()` and 43 `write()` calls honor timeouts. 44 45 * **Easy to implement.** `Source` declares three methods: `read()`, `close()`, 46 and `timeout()`. There are no hazards like `available()` or single-byte reads 47 that cause correctness and performance surprises. 48 49 * **Easy to use.** Although _implementations_ of `Source` and `Sink` have only 50 three methods to write, _callers_ are given a rich API with the 51 [`BufferedSource`][7] and [`BufferedSink`][8] interfaces. These interfaces give you 52 everything you need in one place. 53 54 * **No artificial distinction between byte streams and char streams.** It's all 55 data. Read and write it as bytes, UTF-8 strings, big-endian 32-bit integers, 56 little-endian shorts; whatever you want. No more `InputStreamReader`! 57 58 * **Easy to test.** The `Buffer` class implements both `BufferedSource` and 59 `BufferedSink` so your test code is simple and clear. 60 61 Sources and sinks interoperate with `InputStream` and `OutputStream`. You can 62 view any `Source` as an `InputStream`, and you can view any `InputStream` as a 63 `Source`. Similarly for `Sink` and `OutputStream`. 64 65 Dependable 66 ---------- 67 68 Okio started as a component of [OkHttp][1], the capable HTTP+SPDY client 69 included in Android. It's well-exercised and ready to solve new problems. 70 71 72 Example: a PNG decoder 73 ---------------------- 74 75 Decoding the chunks of a PNG file demonstrates Okio in practice. 76 77 ```java 78 private static final ByteString PNG_HEADER = ByteString.decodeHex("89504e470d0a1a0a"); 79 80 public void decodePng(InputStream in) throws IOException { 81 BufferedSource pngSource = Okio.buffer(Okio.source(in)); 82 83 ByteString header = pngSource.readByteString(PNG_HEADER.size()); 84 if (!header.equals(PNG_HEADER)) { 85 throw new IOException("Not a PNG."); 86 } 87 88 while (true) { 89 Buffer chunk = new Buffer(); 90 91 // Each chunk is a length, type, data, and CRC offset. 92 int length = pngSource.readInt(); 93 String type = pngSource.readUtf8(4); 94 pngSource.readFully(chunk, length); 95 int crc = pngSource.readInt(); 96 97 decodeChunk(type, chunk); 98 if (type.equals("IEND")) break; 99 } 100 101 pngSource.close(); 102 } 103 104 private void decodeChunk(String type, Buffer chunk) { 105 if (type.equals("IHDR")) { 106 int width = chunk.readInt(); 107 int height = chunk.readInt(); 108 System.out.printf("%08x: %s %d x %d%n", chunk.size(), type, width, height); 109 } else { 110 System.out.printf("%08x: %s%n", chunk.size(), type); 111 } 112 } 113 ``` 114 115 Download 116 -------- 117 118 Download [the latest JAR][2] or grab via Maven: 119 ```xml 120 <dependency> 121 <groupId>com.squareup.okio</groupId> 122 <artifactId>okio</artifactId> 123 <version>1.6.0</version> 124 </dependency> 125 ``` 126 or Gradle: 127 ```groovy 128 compile 'com.squareup.okio:okio:1.6.0' 129 ``` 130 131 Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. 132 133 134 [1]: https://github.com/square/okhttp 135 [2]: https://search.maven.org/remote_content?g=com.squareup.okio&a=okio&v=LATEST 136 [3]: http://square.github.io/okio/okio/ByteString.html 137 [4]: http://square.github.io/okio/okio/Buffer.html 138 [5]: http://square.github.io/okio/okio/Source.html 139 [6]: http://square.github.io/okio/okio/Sink.html 140 [7]: http://square.github.io/okio/okio/BufferedSource.html 141 [8]: http://square.github.io/okio/okio/BufferedSink.html 142 [snap]: https://oss.sonatype.org/content/repositories/snapshots/ 143