Android开源项目分析-Okio简介

概述

Okio是一个用来补充 java.io and java.nio 的库,它使访问、存储以及处理数据更加方便。

ByteStrings 和 Buffers

Okio围绕两种类型构建,它们封装了大量功能并提供了简单的API:

  • ByteString是一个不变的字节序列。对于字符数据,String是最基础的。 ByteString 可以看做是Sring长期失散的兄弟,它将String中的字符数据以二进制数据形式看待。这个类知道如何以十六进制、base64、utf-8编码和解码自身。

  • Buffer 是一个可变的字节序列。有点像ArrayList,你不需要去关心buffer大小。以队列形式读写缓存:写数据到队列末尾,从队列头读取数据。这里无需管理位置、限制和容量。

内部来讲, ByteStringBuffer用了一些小技巧来节省CPU和内存,如果你以ByteString形式编码一个UTF-8的字符串,它会缓存一个字符串引用,这样在后面解码时就不需要做任何事。

Buffer用片段的链表来实现。当在缓存间移动数据时,无需拷贝数据,只需设置片段的相关值。这种方式对多线程编程非常有帮助:网络线程能够和工作线程交换数据而无需任何内存拷贝。

Sources 和 Sinks

java.io设计中优雅的部分是如何将转换进行分层,就像加密和压缩。Okio包含它自己的流类型称为SourceSink ,类似于InputStreamOutputStream,但是有一些关键不一样:

  • 超时. 流提供了访问潜在的I/O超时机制。不像java.io socket流,read()write()只是名义上的超时。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.

  • 易于实现. Source定义了三个方法:read(), close()timeout()。它没有像available()一样的危险因素或单个字节读写导致正确性和性能的问题。

  • 易于使用. 尽管SourceSink实现 只有三种方法去写,但是 调用者 有一堆丰富的 BufferedSourceBufferedSink的API接口。这些接口在某些方面能实现任何你想要的。

  • 没有字节流和字符流之间的区别. 都以数据形式看待。读和写都以字节、UTF-8字符串、大端32位整数,小段short。不再需要 InputStreamReader!

  • 易于测试. Buffer类同时实现了BufferedSourceBufferedSink,因此测试代码简单明了。

Sources 和 sinks 能够与InputStreamOutputStream进行互操作。你能够将任何 Source看做是InputStream,同时也能够将任何InputStream看做是SourceSinkOutputStream也是一样。

示例:一个PNG解码器

下面是用Okio来解码PNG文件的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
}
}

相关链接

【1】https://github.com/square/okio