Okio 之初探黄龙
Okio 是一个包装了 java.io
和 java.nio
api 的库,以便可以更容易的访问、存储以及处理数据。
ByteStrings 和 Buffers
Okio 是围绕着两个容器类构建起来的:
ByteString
是一个不可变的字节序列。对于字符数据,Java 中的String
类提供了基本的支持。ByteString
就像是 String 失散多年的兄弟,对二进制数据提供了基本的支持。这个类是非常人性化的:它明白如何编码或解码自身来作为十六进制字符串、base64 字符串或者 UTF-8 字符串。Buffer
是一个可变的字节序列。就像ArrayList
一样,你不需要提前规定你的buffer
的大小。你可以像读写队列一样读写buffer
:写数据到末尾、从头部读数据。你不需要负责管理positions
,limits
, 以及capacities
。
ByteString
和 Buffer
内部做了一些优化以便节省 CPU 和内存资源。如果你把一个 UTF-8 的字符串转换为 ByteString
,ByteString
会缓存这个字符串的引用,之后如果你在解码时就直接返回这个字符串引用即可,无需做什么额外的工作。
Buffer
是由段(segment)链表组成的。当你从一个 Buffer
移动数据到另外一个 Buffer
时,它只是重新设置了段(segment)的拥有者而不是复制数据。这种方法对于多线程程序将是非常有用的:网络线程可以和工作者线程交换数据而无需任何的复制。
Sources 和 Sinks
java.io
原生 API 设计精妙的一处就是流数据可以分层进行转换处理,比如:加密和压缩。就像 InputStream
和 OutputStream
,Okio 也包含了自己的流类型 Source
和 Sink
,但是却有几点关键性的不同之处:
- 超时机制。Okio 的流类型对底层 I/O 访问时增加了超时机制,而
java.io
套接字流的read()
和write()
方法均是永不超时的。 - 实现简单。
Source
类声明了三个方法:read()
,close()
, 和timeout()
,不存在像available()
这种危险的方法或者单字节读取数据这种容易造成性能问题的方法。 - 容易使用。尽管
Source
和Sink
只有三个方法来读写数据,但是调用者可以使用功能丰富的实现类BufferedSource
和BufferedSink
接口。 - 对于字节流和字符流没有人工区别。Okio 中字节流和字符流都是一样的,可以以字节流,UTF-8 字符串,大端 32位整数,小端短整数来读写。不再有
InputStreamReader
。 - 容易测试。
Buffer
类实现了BufferedSource
和BufferedSink
接口,所以你的测试代码将是简单清晰的。
Sources 加 sinks 和 InputStream
加 OutputStream
内部是可以互相操作的。所以你可以把 Source
看做一个 InputStream
,并且也可以把 InputStream
看做一个 Source
;Sink
和 OutputStream
同样如此。
示例:一个 PNG 解码器
package okio;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by clearbug on 2017/11/5.
*/
public class PngDecoder {
private static final ByteString PNG_HEADER = ByteString.decodeHex("89504e470d0a1a0a");
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("/Users/clearbug/Pictures/Small-mario.png");
PngDecoder pngDecoder = new PngDecoder();
pngDecoder.decodePng(inputStream);
}
public void decodePng(InputStream in) throws IOException {
try (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;
}
}
}
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);
}
}
}
Okio 之初探黄龙的更多相关文章
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
- CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探
CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...
- 从273二手车的M站点初探js模块化编程
前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...
- JavaScript学习(一) —— 环境搭建与JavaScript初探
1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...
- .NET文件并发与RabbitMQ(初探RabbitMQ)
本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...
- React Native初探
前言 很久之前就想研究React Native了,但是一直没有落地的机会,我一直认为一个技术要有落地的场景才有研究的意义,刚好最近迎来了新的APP,在可控的范围内,我们可以在上面做任何想做的事情. P ...
- 【手把手教你全文检索】Apache Lucene初探
PS: 苦学一周全文检索,由原来的搜索小白,到初次涉猎,感觉每门技术都博大精深,其中精髓亦是不可一日而语.那小博猪就简单介绍一下这一周的学习历程,仅供各位程序猿们参考,这其中不涉及任何私密话题,因此也 ...
- Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用
一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...
- NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例
一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...
随机推荐
- Visual Studio 调试技巧[Command Window & Immediate Window ](Tips)
Visual Studio 调试技巧[Command Window & Immediate Window ](Tips) 1. immediate window 定义的一些 alias (// ...
- Winsock网络编程笔记(3)----基于UDP的server和client
在上一篇随笔中,对Winsock中基于tcp面向连接的Server和Client通信进行了说明,但是,Winsock中,Server和Client间还可以通过无连接通信,也就是采用UDP协议.. 因此 ...
- Nginx HTTP 核心模块
原文链接:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=17238776&id=2982697aio 语法:aio [ ...
- Flex中宽度计算
flex 有三个属性值,分别是 flex-grow, flex-shrink, flex-basis,默认值是 0 1 auto. 发现网上详细介绍他们的文章比较少, 今天就详细说说他们,先一个一个看 ...
- URI 方法 encodeURI() encodeURIComponent() docodeURI() decodeURIComponent()
URI 方法 encodeURI() encodeURIComponent() docodeURI() decodeURIComponent() var sUri = “http://ww ...
- display:table 表格布局
table 布局最大的特点 1.同行等高 2.宽度自动调节 那么table-cell是不是具备这个特点呢?答案是yes,为什么呢?css中有一个有意思的规则“创建匿名表格元素”. 拿table ...
- 密码学那些事———SHA-512及其C++实现
SHA-512及其C++实现 转载请注明出处 一.引言 相信大家对于哈希压缩加密算法应该不陌生,在我们用微信或者支付宝接口的时候经常会遇到用这类算法加密,以验证数据的完整性.可以说这类算法无处不在,那 ...
- Ruby变量常量
全局变量:以$开头 实例变量:以@开头 @cust_id=id Ruby 常量: 常量以大写字母开头
- 在微信端使用video标签,播放结束会出现QQ浏览器推荐视频的解决办法(vue)
会出现播放结束显示QQ浏览器推荐视频的原因:(我是vue的项目,而且我是新手,只是单纯的给大家分享一个方法,代码比较low请自动忽略) 因为在x5(QQ浏览器)内核中,把video标签劫持了,只要是检 ...
- javascript 中遍历数组的简单方法
在Javascript中有自带方便遍历数组的方法(此方法非彼方法不要误会哦): 1 .利用for( index in array ){}; 2.利用 array.forEach( function(e ...