You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.1 KiB
143 lines
5.1 KiB
7 months ago
|
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/
|