• Okio 之初探黄龙


    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);
            }
        }
    }
    
  • 相关阅读:
    如何通过npm编译Typescript代码
    TypeScript 中的':' 和'?:'的区别
    无法读取本地服务器JSON文件, 返回404错误
    Nodejs , npn 注册 包上传,更新,下载
    Java 字符流
    Java 字节流
    Java中的File类,递归是什么?
    JDBC工具类—如何封装JDBC
    JDBC的开发步骤
    vFor和vIf不要一起使用
  • 原文地址:https://www.cnblogs.com/optor/p/7786925.html
Copyright © 2020-2023  润新知