• NIO


    概念(NIO vs BIO)

    NIO, Non-blocking I/O, 非阻塞式 I/O 模型。也可以解释为 New I/O, 区别于旧的阻塞式 I/O 模型(BIO)。

    BIO 与 NIO 的区别如下:

    类别 I/O 方式 最低可用的 JDK 版本
    BIO 流式 JDK 1.0
    NIO 块式 JDK 1.4

    所谓流式处理,就是单个字节的数据移动,通过一个称为 Stream 的对象一次移动一个字节;而块式处理,就是单个字节数组的数据移动,通过一个叫 Buffer 的对象一次移动一个字节数组。JDK 中的 NIO 库已经集成了原来的标准 I/O 功能。

    缓冲区和通道(Buffer & Channel)

    NIO 中的缓冲区(Buffer)实质是一个数组,通常为字节数组(ByteBuffer),用作读写缓冲,以及对数据的结构化访问,还可以用来跟踪系统的读写进程。

    Buffer 类型:

    • ByteBuffer
    • CharBuffer
    • ShortBuffer
    • IntBuffer
    • LongBuffer
    • FloatBuffer
    • DoubleBuffer

    NIO 中的通道(Channel)类似 BIO 中的流(Stream),但是是双向的,可以用来读、写或者同时读写。流之所以是单向的,是因为一个 Stream 要么是 InputStream,要么是 OutputStream,不能兼有。

    缓冲区内部细节(Buffer Internals)

    状态变量(State Variables)

    • Position,表征读了或写了多少数据到数组中,指向下一个元素的位置;
    • Limit,表征剩余可读或可写的的数据量,初始情况下 Limit = Capacity。
    • Capacity,表征 Buffer 的最大容量。

    三者关系:Position <= Limit <= Capacity

    下面从微观角度观察各状态变量在读写操作中的变化:

    (1) Init

    初始状态下,Position 指向第一个元素的位置,Limit 和 Capacity 指向最后一个元素的下一个虚拟元素的位置。由于 Capacity 保持不变,下面的讨论中予以略过。

    (2)Channel.read

    读取 5 个元素到缓冲区后,Position 指向第六个元素的位置,Limit 不变。

    (3)Buffer.flip

    进行 Flip 操作后,Limit 指向当前的 Position 的位置,Position 指回第一个元素的位置,

    (4)Channel.write

    从缓冲区读取 5 个元素写入 Channel 后,Position 指向 Limit 所在的位置。

    (5)Buffer.clear

    clear 后缓冲区重置到初始状态。

    存取方法(Accessor )

    存取方法分为:

    • 相对方法(Relative Method):在当前 position 进行读写操作,随后 position 自增1。
    • 绝对方法(Absolute Method):在某个索引位置进行读写操作,不影响 position 和 limit。

    (1)get 系列方法(包括 array() ),用于读取缓冲区的数据,其中 byte get(int index) 为绝对方法。

    (2)put 系列方法,用于写入数据到缓冲区,其中 ByteBuffer put(int index, byte b) 为绝对方法。

    使用(Show U the Code)

    读取文件

    1. 从 FileInputStream 中获取 Channel;
    2. 创建 Buffer;
    3. 将数据从 Channel 读到 Buffer 中。

    示例如下:

    // 将 a_file 读到 StringBuilder 中
    FileInputStream fin = new FileInputStream("/path/to/a_file");
    FileChannel fc = fin.getChannel();
    
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    StringBuilder sb = new StringBuilder();
    while (fc.read(buffer) != -1) {
        sb.append(new String(buffer.array(), 0, buffer.position()));
    }
    

    写入文件

    1. 从 FileOutputStream 中获取 Channel;
    2. 创建 Buffer;
    3. 写入数据到 Buffer;
    4. 将数据从 Buffer 写入 Channel 中。

    示例如下:

    // 将 "Something" 写入 a_file 中
    FileOutputStream fos = new FileOutputStream("/path/to/a_file");
    FileChannel fc = fos.getChannel();
    
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    
    byte[] content = "Something".getBytes();
    for (byte aContent : content) {
        buffer.put(aContent);
    }
    buffer.flip();
    
    fc.write(buffer);
    

    边读边写

    1. 清除 Buffer;
    2. 从输入流的 Channel 读数据到 Buffer;
    3. 写入 Buffer 中的数据到输出流的 Channel;
    4. 循环直到输入流的 Channel 中没有数据。

    示例如下:

    FileInputStream fin = new FileInputStream("path/to/in_file");
    FileOutputStream fout = new FileOutputStream("path/to/out_file");
    
    FileChannel fcin = fin.getChannel();
    FileChannel fcout = fout.getChannel();
    
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    
    while (true) {
        buffer.clear();
        int r = fcin.read(buffer);
        if (r == -1) {
            break;
        }
        buffer.flip();
        fcout.write(buffer);
    }
    

    参考

    写在后面:

    1. 子曰:「学而不思则罔,思而不学则殆」。
    2. 站点地图
    2. 本作品作者为 Lshare,采用知识共享署名 4.0 国际许可协议进行许可。
  • 相关阅读:
    C#撸了个批量转换Word、Excel、PPT为PDF的软件 pdfcvt.com
    关于《图解国富论》若干问题的思考《六》
    关于《图解国富论》若干问题的思考《五》
    关于《图解国富论》若干问题的思考《四》
    关于《图解国富论》若干问题的思考《三》
    关于《图解国富论》若干问题的思考《二》
    关于《图解国富论》若干问题的思考《一》
    忆秦娥·娄山关
    《动物精神》笔记
    《非理性繁荣》笔记
  • 原文地址:https://www.cnblogs.com/lshare/p/11334397.html
Copyright © 2020-2023  润新知