- 工程说明
:
okio是Square开源框架 之一,它对java.io和java.nio做了补充,使访问,存储和数据处理变得更加容易。它最早是Okhttp组件之一 - 分支说明:本文选取1.x分支源码(JAVA代码)分析
master
* okio_1x
remotes/origin/HEAD -> origin/master
remotes/origin/egorand/200216/buffer-nsdata
remotes/origin/gh-pages
remotes/origin/ghpages-javadocs
remotes/origin/jakew/top-level-common/2019-04-04
remotes/origin/jwilson.0207.zip
remotes/origin/jwilson.0209.zipzip
remotes/origin/jwilson.0306.relative_list
remotes/origin/jwilson.0424.arrays
remotes/origin/jwilson.0515.windows_file_handle
remotes/origin/jwilson.0523.js
remotes/origin/jwilson.0601.toFraction_toIndex
remotes/origin/jwilson.0722.copyInto
remotes/origin/jwilson.0723.aoobe_rm
remotes/origin/jwilson.1101.coroutines
remotes/origin/master
remotes/origin/okio_1_14
remotes/origin/okio_1x
remotes/origin/okio_2_4
remotes/origin/okio_2x
remotes/origin/ray/new-hotness-structure
- 按照使用代码流程分析源码实现过程
Okio包含自己的流类型,称为Source和Sink,其工作方式虽然类似InputStream和OutputStream,但它与Java I/O相比具有以下优势(参考自Android学习笔记——Okio):
- Okio实现了I/O读写的超时机制(Timeout),防止读写出错从而导致一直阻塞。
- N合一,OKIO精简了输入输出流的类个数
- 低的CPU和内存消耗,引入Segment和SegmentPool复用机制
- 使用方便。ByteString处理不变byte,Buffer处理可变byte。
- 提供了一系列的工具。OKIO支持md5、sha、base64等数据处理
Source、Sink可以与InputStream、OutputStream互相操作。我们可以将任何Source视为InputStream,也可以将任何InputStream视为Source。同样适用于Sink和InputStream。
//从文件读取数据
File sourceFile = new File("path");
Source source = Okio.source(sourceFile);
BufferedSource bufferedSource = Okio.buffer(source);
byte[] allByte = bufferedSource.readByteArray();
1、先看OKio.source(sourceFile),此方法中返回了一个匿名内部类,实现read、close等方法,依赖InputString对象;read函数中主要从inputStream中读取最大8Kb大小数据的内容;
public static Source source(File file) throws FileNotFoundException {
if (file == null) {
throw new IllegalArgumentException("file == null");
} else {
return source((InputStream)(new FileInputStream(file)));
}
}
private static Source source(final InputStream in, final Timeout timeout) {
if (in == null) {
throw new IllegalArgumentException("in == null");
} else if (timeout == null) {
throw new IllegalArgumentException("timeout == null");
} else {
return new Source() {
public long read(Buffer sink, long byteCount) throws IOException {
if (byteCount < 0L) {
throw new IllegalArgumentException("byteCount < 0: " + byteCount);
} else if (byteCount == 0L) {
return 0L;
} else {
try {
timeout.throwIfReached();
Segment tail = sink.writableSegment(1);
int maxToCopy = (int)Math.min(byteCount, (long)(8192 - tail.limit));
int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
if (bytesRead == -1) {
return -1L;
} else {
tail.limit += bytesRead;
sink.size += (long)bytesRead;
return (long)bytesRead;
}
} catch (AssertionError var7) {
if (Okio.isAndroidGetsocknameError(var7)) {
throw new IOException(var7);
} else {
throw var7;
}
}
}
}
public void close() throws IOException {
in.close();
}
public Timeout timeout() {
return timeout;
}
public String toString() {
return "source(" + in + ")";
}
};
}
}
2、BufferedSource bufferedSource = Okio.buffer(source)代码流程,OKio.buffer代码如下,buffer是一个接口,真正返回一个RealBufferedSource(source)对象;
public static BufferedSource buffer(Source source) {
return new RealBufferedSource(source);
}
3、byte[] allByte = bufferedSource.readByteArray()代码流程,RealBufferedSource.readByteArray(),
- writeAll函数的作用是从inputStream对接中读取所有数据,并通过segment链表保存;
- buffer.readByteArray(),从上面保存的segment中copy数据到byte[ ]数组,具体由代码(2)(3)(4)三个函数实现,readFully(byte[] result)for循环从segment链表中获取数据;
public byte[] readByteArray() throws IOException {
this.buffer.writeAll(this.source);
return this.buffer.readByteArray();
}
---------------------------------------(1)-------------------------------------------
public long writeAll(Source source) throws IOException {
if (source == null) {
throw new IllegalArgumentException("source == null");
} else {
long totalBytesRead;
long readCount;
for(totalBytesRead = 0L; (readCount = source.read(this, 8192L)) != -1L; totalBytesRead += readCount) {
}
return totalBytesRead;
}
}
---------------------------------------(2)-------------------------------------------
public byte[] readByteArray() {
try {
return this.readByteArray(this.size);
} catch (EOFException var2) {
throw new AssertionError(var2);
}
}
---------------------------------------(3)-------------------------------------------
public byte[] readByteArray(long byteCount) throws EOFException {
Util.checkOffsetAndCount(this.size, 0L, byteCount);
if (byteCount > 2147483647L) {
throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
} else {
byte[] result = new byte[(int)byteCount];
this.readFully(result);
return result;
}
}
----------------------------------------(4)------------------------------------------
public void readFully(byte[] sink) throws EOFException {
int read;
for(int offset = 0; offset < sink.length; offset += read) {
read = this.read(sink, offset, sink.length - offset);
if (read == -1) {
throw new EOFException();
}
}
}
-----------------------------------------(5)-----------------------------------------
public int read(byte[] sink, int offset, int byteCount) {
Util.checkOffsetAndCount((long)sink.length, (long)offset, (long)byteCount);
Segment s = this.head;
if (s == null) {
return -1;
} else {
int toCopy = Math.min(byteCount, s.limit - s.pos);
System.arraycopy(s.data, s.pos, sink, offset, toCopy);
s.pos += toCopy;
this.size -= (long)toCopy;
if (s.pos == s.limit) {
this.head = s.pop();
SegmentPool.recycle(s);
}
return toCopy;
}
}
4、到此已完成source怎么从FileInputStream中获取数据并返回到byte数组的源码分析,下一篇分析Sink输出数据流程
参考博客:https://blog.csdn.net/lmh_19941113/article/details/86726961