Okio总体上来说是对io操作的一种良好封装。操作方便,性能也比系统自带的要好。
操作上的方便性:
用了外观模式,将Stream File Socket的读操作封装成了Source接口,将Stream File Socket的写操作封装成了Sink接口
Okio.source 和 Okio.sink方法可以将上述三种类型封装成统一的接口。
为了使更方便点,不用关心数据拷贝,和存储数据空间管理问题又封装了BufferedSource,BufferedSink。
这两个接口里面有使用率频率很高的读写接口,包括字符读取,long,int等数据类型读写,不再面向byte操作
public void readLines(File file) throws IOException {
try (BufferedSource source = Okio.buffer(Okio.source(file))) {
for (String line; (line = source.readUtf8Line()) != null; ) {
if (line.contains("square")) {
System.out.println(line);
}
}
}
}
public void writeEnv(File file) throws IOException {
try (Sink fileSink = Okio.sink(file);
BufferedSink bufferedSink = Okio.buffer(fileSink)) {
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
bufferedSink.writeUtf8(entry.getKey());
bufferedSink.writeUtf8("=");
bufferedSink.writeUtf8(entry.getValue());
bufferedSink.writeUtf8("\n");
}
}
}
是不是清爽很多
在BufferedSource,BufferedSink接口之下隐藏的实现细节在RealBufferedSink,RealBufferedSource这两个类里面,这两个类里面采用Buffer实现,而Buffer内部与Segment相配合,Buffer和Segment是Okio的核心了。 Segment相当于原来我们相当朴素的写法中new出来的那个byte数组,Buffer内部需要要一个Segment时,就会从SegmentPool拿一个。
Segment内部封装了一个大小为8192大小的字节数组。
性能提升:
性能的提升在于减少字节拷贝,java内部实现的BufferedInputStream BufferedOutputStream内部维护一个8192大小的字节数组。
写入数据时我们需要两个操作,首先将数据变换为byte数组,并写入我们自己准备buf内 然后将buf通过write接口写入内部的buf。
这里其实是有两次拷贝的。
而okio中我们只需拷贝一次。
Segment里还有shared字段,可以与其他Segment共享buf。
超时功能:
普通的TimeOut功能是在每次读写时看一下是不是到了deadline时间,或线程被interrupt socket的TimeOut是在WatchDog线程内轮询,查找并回调timeout接口,在回调中close socket