一文详解 Okio 输入输出流

在 OkHttp 的源码中,我们经常能看到 Okio 的身影,这篇文章,我们把Okio拿出来进行一个详细的介绍学习。

  • 输入输出的概念简述
  • Okio 简介
  • 工程中引入 Okio
  • API 简介及使用介绍

一、输入输出

在正式介绍 Okio 之前,让我们先回忆一下输入/输出流的概念。

  • 输入流:外设——>内存
    将数据从各种外设(如键盘、文件、网络、数据库等)读取到内存中;
    一文详解 Okio 输入输出流
  • 输出流:内存——>外设
    与输入流相反,是将内存数据写入到各种外设(如文件、网络、数据库、显示器等);
    一文详解 Okio 输入输出流

二、Okio简介

Okio最初是作为OkHttp的一个组件出现,是 OkHttp 实现HTTP协议数据构建、解析中使用到的底层 IO 库。其相比于传统的 java.io 和 java.nio ,其在文件网络等数据读写操作更加便捷、高效

一文详解 Okio 输入输出流

Okio 的设计思想是将数据的读写操作封装为一个统一的接口,即 SourceSink,其中 输入为Source,输出为Sink

  • Okio 还提供了 BufferByteString 用于封装和操作字节数据,提高数据读写的效率。
  • 同时,Okio 还提供了一些工具方法,例如从 InputStreamOutputStream 中创建 BufferedSourceBufferedSink 等。

三、引入Okio

Okio官方API地址为:
https://square.github.io/okio/

Okio Github开源地址为:
https://github.com/square/okio

使用 Okio 时,我们可以查阅官方最新版本,并通过如下方式引入Okio:

implementation("com.squareup.okio:okio:3.2.0") 

四、API 简介及使用

  • Buffer 简介及API使用介绍
  • ByteString 简介及API使用介绍
  • Source 和 Sink 使用介绍

4.1 Buffer

Buffer一个大小可变的字节缓冲区,在Okio中BufferBufferedSourceBufferedSink的接口实现类,用户实现字节数据的缓冲与读写。

官方API描述如下:
一文详解 Okio 输入输出流

  • Buffer可以像Arraylist一样,不需要预先设置缓冲区的大小,而是随着数据的增加自动扩充缓冲区大小
  • Buffer由很多的Segment片段构成,每个Segment中维护一个字节数组
  • Buffer中以链表的形式来管理Segment,当使用Buffer进行缓冲区字节数据移动时,其只改变Segment字节数组的所有权,从而提高字节数组的移动效率。

okio.Buffer字节缓冲区的使用方式举例如下:

import okio.Buffer;  Buffer buffer = new Buffer(); // 向缓冲区写入数据 buffer.writeUtf8("key"); buffer.writeByte('='); buffer.writeUtf8("value");  // 缓冲区字节大小 int byteCount = buffer.size();  // 读取换区中的全部字节数据 byte[] byteArray = buffer.readByteArray(); // 以Utf8编码的形式输出所有字符串 String result = buffer.readUtf8();  // 清空缓冲区 buffer.clear(); 

4.2 ByteString

ByteString 中维护了大小不可变的字节数组,其可以对存入该字节数组的数据进行base64utf8md5sha256等字符串的编解码操作。
ByteString 更像是一个工具类,在Okio中其重要应用场景也是在网络传输中对数据进行编码和解码工作

官方API描述如下:
一文详解 Okio 输入输出流

其部分静态方法和公有方法如下图所示:

一文详解 Okio 输入输出流

一文详解 Okio 输入输出流

okio.ByteString的使用方式举例如下:

import okio.ByteString;  // utf8编码 ByteString byteString = ByteString.encodeUtf8("hello"); // HEX ByteString byteString = ByteString.decodeHex("hello"); // 输出utf8字符串 String result = byteString.utf8(); 

4.3 Source 和 Sink

Source 和 Sink 在前文中提到过输入为Source,输出为Sink。在 Okio 中,SourceSink 用于读取写入数据的抽象类,其提供了一组标准的IO读写方法,可以方便地进行数据的读写操作。

// Okio源码:输入流 Source // Source 接口类,最主要的方法是 read public interface Source extends Closeable { 	// 读字节数据     long read(Buffer var1, long var2) throws IOException;     // timeout     Timeout timeout();     void close() throws IOException; } // Okio源码:输出流 Sink  // Sink 接口类,最主要的方法是 write public interface Sink extends Closeable, Flushable { 	// 写字节数据     void write(Buffer var1, long var2) throws IOException;     void flush() throws IOException;     Timeout timeout();     void close() throws IOException; } 

在把前文已经展示过的Okio结构图拿出来:

  • Source的最终实现类是RealBufferedSource
  • Sink的最终实现类是RealBufferedSink

一文详解 Okio 输入输出流

使用 okio.Source 从文件中读取数据,代码举例如下:

// 使用 Source 从文件中读取数据 public static void readLines(File file) throws IOException {     // 输入流     Source fileSource = Okio.source(file);     // 构建 BufferedSource     RealBufferedSource bufferedSource = Okio.buffer(fileSource);     // 循环读取     while (true) {         // 读取行数据         String line = bufferedSource.readUtf8Line();         if (line == null) {             break;         }     } }  

使用 okio.Sink 向文件中写入数据,代码举例如下:

// 使用 Sink 向文件中写入数据 public static void writeToFile(File file) throws IOException { 	// 创建输出流     Sink fileSink = Okio.sink(file);     // 构造 BufferedSink     RealBufferedSink bufferedSink = Okio.buffer(fileSink);     // 向文件中写入数据     bufferedSink.writeUtf8("Hello");     bufferedSink.writeUtf8("n");     bufferedSink.writeAll(Okio.source(new File("my.txt"))); } 

五、参考

Okio API:
https://square.github.io/okio/

Okio Github:
https://github.com/square/okio

Java流:
http://c.biancheng.net/view/1119.html

= THE END =

文章首发于公众号”CODING技术小馆“,如果文章对您有帮助,欢迎关注我的公众号。
一文详解 Okio 输入输出流

发表评论

评论已关闭。

相关文章