NIO学习 - Buffer

总结一下关于 NIO 的知识。(jdk1.7)

NIO(Non-blocking IO 或称为 New IO)是JavaSE1.4 出的新特性,就我当前的了解,它优化了 IO 性能,并支持非阻塞 IO 操作。

对于 IO 性能的优化,主要集中在 Channel 和 Buffer 上,今天先说Buffer。

看一眼 接口Buffer 的源码:
Buffer.java

// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

Buffer(int mark, int pos, int lim, int cap) {   // package-private
    this.capacity = cap;
    limit(lim);
    position(pos);
    ...
}

初始化主要是对4个int类型的变量赋初值。

再看一眼一个具体实现类 ByteBuffer 的源码,
ByteBuffer.java

ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset)  // package-private
{
    super(mark, pos, lim, cap);
    this.hb = hb;
    this.offset = offset;
}

public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
    // HeapByteBuffer 继承自 ByteBuffer
}

可以看到,ByteBuffer缓冲区的底层是用 byte[] 实现的,并且ByteBuffer的构造方法并没有公开,我们可以通过 ByteBuffer.allocate( int capacity ) 来获取一个容量为 capacity 的 ByteBuffer。

来画一下这个 Buffer,先不考虑 mark,结合Buffer构造中能看到的属性,并且有 position(位置) <= limit(极限) <= capacity(容量),那一个容量为8的 Buffer 大概就是这样:

这里写图片描述

要了解这几个数值的作用,先看下面的代码:
这里的 fileChannel.read(byteBuffer) 的作用是把 fileChannel 中的数据写入 byteBuffer。

ByteBuffer byteBuffer = ByteBuffer.allocate(8);

int bytesRead = fileChannel.read(byteBuffer);
while (bytesRead != -1) {
    byteBuffer.flip();
    while(byteBuffer.hasRemaining()){
        System.out.print((char) byteBuffer.get());
    }
    byteBuffer.clear();  //清空缓冲区
    bytesRead = fileChannel.read(byteBuffer);
}

能进入外层 while 循环,说明 byteBuffer 中被写入了数据。内层 while 循环的作用是 输出 byteBuffer 中的读到到数据,byteBuffer.get() 在子类 HeapByteBuffer 中实现
return hb[ix(nextGetIndex())];
返回下一单元的数据。
byteBuffer.clear():极限设为容量,位置设为0,相当于清空了缓冲区,便于下次读入数据。
我们假设本次读入了5个 byte 的数据,Buffer那大概就是这样:

这里写图片描述

所以,byteBuffer.flip();的作用是什么呢?

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

flip 之后

这里写图片描述

显而易见,flip标识出了本次读入数据的起止位置。也就是准备好了数据读取的位置和上限,get方法是从position开始的,这时使用 while{buffer.get()}就可以顺利读取了。并且,如果上一次写入了8个数据,本次写入了5个,那么本次只能读取到5个,而不能读取到上次写入后未被覆盖的3个数据。

另:
1. 也可用 ByteBuffer.allocateDirect(int capacity) 得到 ByteBuffer,速度快但有其他代价;
2. get()相对读,get(int index)为绝对读;相应的 put()相对写,put(int index)绝对写。均只能读写一个byte。
3. Buffer 的其他实现还有:ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer、MappedByteBuffer。

明天说Channel。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值