Okio 是一个包装了 java.iojava.nio api 的库,以便可以更容易的访问、存储以及处理数据。

ByteStrings 和 Buffers

Okio 是围绕着两个容器类构建起来的:

  • ByteString 是一个不可变的字节序列。对于字符数据,Java 中的 String 类提供了基本的支持。ByteString 就像是 String 失散多年的兄弟,对二进制数据提供了基本的支持。这个类是非常人性化的:它明白如何编码或解码自身来作为十六进制字符串、base64 字符串或者 UTF-8 字符串。
  • Buffer 是一个可变的字节序列。就像 ArrayList 一样,你不需要提前规定你的 buffer 的大小。你可以像读写队列一样读写 buffer:写数据到末尾、从头部读数据。你不需要负责管理 positions, limits, 以及 capacities

ByteStringBuffer 内部做了一些优化以便节省 CPU 和内存资源。如果你把一个 UTF-8 的字符串转换为 ByteStringByteString 会缓存这个字符串的引用,之后如果你在解码时就直接返回这个字符串引用即可,无需做什么额外的工作。

Buffer 是由段(segment)链表组成的。当你从一个 Buffer 移动数据到另外一个 Buffer 时,它只是重新设置了段(segment)的拥有者而不是复制数据。这种方法对于多线程程序将是非常有用的:网络线程可以和工作者线程交换数据而无需任何的复制。

Sources 和 Sinks

java.io 原生 API 设计精妙的一处就是流数据可以分层进行转换处理,比如:加密和压缩。就像 InputStreamOutputStream,Okio 也包含了自己的流类型 SourceSink ,但是却有几点关键性的不同之处:

  • 超时机制。Okio 的流类型对底层 I/O 访问时增加了超时机制,而 java.io 套接字流的 read()write() 方法均是永不超时的。
  • 实现简单。Source 类声明了三个方法:read(), close(), 和 timeout(),不存在像 available() 这种危险的方法或者单字节读取数据这种容易造成性能问题的方法。
  • 容易使用。尽管 SourceSink 只有三个方法来读写数据,但是调用者可以使用功能丰富的实现类 BufferedSourceBufferedSink 接口。
  • 对于字节流和字符流没有人工区别。Okio 中字节流和字符流都是一样的,可以以字节流,UTF-8 字符串,大端 32位整数,小端短整数来读写。不再有 InputStreamReader
  • 容易测试。Buffer 类实现了 BufferedSourceBufferedSink 接口,所以你的测试代码将是简单清晰的。

Sources 加 sinks 和 InputStreamOutputStream 内部是可以互相操作的。所以你可以把 Source 看做一个 InputStream,并且也可以把 InputStream 看做一个 SourceSinkOutputStream 同样如此。

示例:一个 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 之初探黄龙的更多相关文章

  1. 初探领域驱动设计(2)Repository在DDD中的应用

    概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...

  2. CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探

    CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...

  3. 从273二手车的M站点初探js模块化编程

    前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...

  4. JavaScript学习(一) —— 环境搭建与JavaScript初探

    1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...

  5. .NET文件并发与RabbitMQ(初探RabbitMQ)

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...

  6. React Native初探

    前言 很久之前就想研究React Native了,但是一直没有落地的机会,我一直认为一个技术要有落地的场景才有研究的意义,刚好最近迎来了新的APP,在可控的范围内,我们可以在上面做任何想做的事情. P ...

  7. 【手把手教你全文检索】Apache Lucene初探

    PS: 苦学一周全文检索,由原来的搜索小白,到初次涉猎,感觉每门技术都博大精深,其中精髓亦是不可一日而语.那小博猪就简单介绍一下这一周的学习历程,仅供各位程序猿们参考,这其中不涉及任何私密话题,因此也 ...

  8. Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  9. NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例

    一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...

随机推荐

  1. C++ 空间配置器(allocator)

    C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...

  2. Ubuntu下通过makefile生成静态库和动态库简单实例

    本文转自http://blog.csdn.net/fengbingchun/article/details/17994489 Ubuntu环境:14.04 首先创建一个test_makefile_gc ...

  3. Android 开发笔记___SD卡基本操作__图片读取写入

    package com.example.alimjan.hello_world.Utils; import android.graphics.Bitmap; import android.graphi ...

  4. mongodb集群【】

    参考 http://www.jianshu.com/p/2825a66d6aed http://www.cnblogs.com/huangxincheng/archive/2012/03/07/238 ...

  5. 手机网站的tips[转载]

    原文:http://www.haorooms.com/post/phone_web 1. 安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经 ...

  6. VUE插件-图片濑加载

    1.  cnpm install vue-lazyload 2.main.js import  vue-lazyload from  'vue-lazyload' Vue.use(vue-lazylo ...

  7. 大家好,我是ZCDHJ

    大家好,我是ZCDHJ.CJ C2017级的一名Oier.

  8. VUE父子组件传值问题

    一.父组件向子组件传递数据 组件实例的作用域是孤立的.这意味着不能(也不应该)在子组件的模板内直接引用父组件的数据.要让子组件使用父组件的数据,我们需要通过子组件的props选项. 1.静态props ...

  9. WPF字符串中的换行符

    <sys:String x:Key="NewUpdateWillShow" xml:space="preserve">第一行 第二行 </sy ...

  10. 33.Linux-实现U盘自动挂载(详解)

    1.当我们每次插入u盘后,都会自动创键U盘的设备节点/dev/sda%d 这是因为里面调用了device_create()实现的, busybox的mdev机制就会根据主次设备号等信息,在/dev下创 ...