NIO的参考文档
1 http://blog.sina.com.cn/s/blog_81c2545a01011afh.html
只要是网络操作,就涉及到IO读写,那自然离不开数据缓存。
NIO作为Netty的异步IO提供商,内部的缓冲区是各种各样的Buffer子类。
所以掌握Buffer是非常有必要的。
正所谓“工欲善其事,必先利其器”嘛。
---------------------------------------------------------------------------
常用的就是ByteBuffer,所以下面以此为例子,(喜欢字节,封装神马的最让人痛恨!!!)
分配
ByteBuffer buffer = ByteBuffer.allocate(100); 分配一个100字节容量的缓冲区
byte[] data=buffer.array(); 直接获取其内部存储对象,可直接修改,
请注意这里的修改是真实的修改缓冲区对应的存储对象。
所以不需要再次对缓冲区buffer进行操作就可以保留修改。
直接分配
《JAVA网络编程》P353 ---除非性能是个问题,否则不应考虑使用此类型的直接缓冲区
包装
实际上就是构造时初始化一些内容。有点类似于malloc和calloc的区别。
包装与分配的区别在于:
分配是重新构造一个新的数组,然后传给某个构造函数。
包装是直接引用之前内容所在的数组,然后传给某个构造函数。
本质都是一样的。
---
填充的例子:
可见pos慢慢增加,pos其实就是下一个可写入的位置,当没有填入任何东西时,pos自然是0.
----------------------------------------------------------------------------------------------------
缓冲区最多只能填充到最大容量,否则会报错,比如:
其实报错的逻辑是这样的:
public ByteBuffer put(byte x) {
hb[ix(nextPutIndex())] = x;
return this;
}
但是在计算nextPutIndex会做校验,校验的代码是这样的:
final int nextPutIndex() { // package-private
if (position >= limit)
throw new BufferOverflowException();
return position++;
}
不难理解了吧。
------------------------------------------------------------------------------------
其实根据打印的信息,此时的那些position limit capacity,
基本表示的意思就是:下一个可写入的字符位置 ,最大可写入字符位置(哨兵角色),总容量个数。
这个从上面的nextPutIndex通过position和limit比较也验证了这一点。
------------------------------------------------------------------------------------
此时,如果写入结束的话,想读取,就必须执行一个flip函数。
为啥变成了pos=0,lim=5,cap=12呢。
其实也就是说:你不是想读取么,好啊,下一个可读取的位置是0,最多可以读到5,总的缓存区容量还是12个。
这个是为读做了一个准备!下面就真的可以开始读取了!
我们看看hasRemaining()的代码,我猜是把pos跟lim比较,
public final boolean hasRemaining() {
return position < limit;
}
代码果然如此。
再看看get,是把position当前位置的内容返回,然后把position自增一个。
毫无秘密可言,真是蛋疼,我还是喜欢C的简单直白。
简单粗暴,不那么多废话。
===========================================
除了利用ByteBuffer提供的各种啰嗦API之外,如果你喜欢简单粗暴的方法的话。
ByteBuffer也满足你。(控制狂专用API)
buffer.put(index,'H');
buffer.get(index);
因为你直接指定了index.
看一看代码实现:
public byte get() {
return hb[ix(nextGetIndex())];
}
public byte get(int i) {
return hb[ix(checkIndex(i))];
}
就不用我多说啥了。
究极控制狂的方法:
byte[] data = buffer.array();
好吧,你厉害,你拿到了缓冲区的数组,连指示器都不要了,
你就把它当做一个数组来用吧。
话说,如果这样做的话,还要ByteBuffer干嘛。:)
因为如果你直接操作一个数组的话,你还是需要若干指示器。
--------------------------------------------
ByteBuffer同样提供了批量操作方法,原理都是一样,
这里我就不给API了,自己去看代码吧。
--------------------------------------------
视图缓冲区
哎,还能不能给人自我控制的感觉了,封装这么多干嘛。。。
压缩缓冲区
也就是说,你之前正在写,写了一半,然后还剩下若干字节
这若干字节左边是空的,右边是空的。
这不是很尴尬嘛,要是把中间这几个字节挪到最左边从0开始就好了。
compact就是干这个的,汗。
很简单,没啥好说的了。
JAVA就是折腾。。。