posts - 12, comments - 0, trackbacks - 0, articles - 7
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

NIO buffer

Posted on 2011-12-18 21:10 cooperzh 阅读(361) 评论(0)  编辑  收藏 所属分类: NIO
ByteBuffer buffer = ByteBuffer.allocate(int);
ByteBuffer buffer = ByteBuffer.allocateDirect(int);
allocate返回的其实是ByteBuffer的子类HeapByteBuffer;
allocateDirect返回的其实是MappedByteBuffer的子类DirectByteBuffer;

CharBuffer.allocate(int cap); 创建的是char[]数组,即cap是char的数量,而不是byte的数量(1个char长度为2个byte)

buffer的四个属性
0 <= mark <= position <= limit <= capacity

buffer支持级联调用:
buffer.position(2).mark().position(4);
因为position,mark方法返回的都是buffer的引用

position决定了read和write的起始位置,小于position位置的char都忽略

buffer.get() 和 buffer.put(byte) 都是相对方法,都会导致position++
buffer.get(int) 和 buffer.put(int,byte) 都是绝对方法,不会导致position变化

buffer.clear() 只是将position置为0,limit设置为capacity,并不真正清空数据

buffer.position(int) 当 newPosition < mark 时,丢弃mark(设置mark=-1)

buffer.mark() 将 position赋值给 mark ;
buffer.reset() 将 mark 赋值给 position;

buffer.remaining() 表示position到limit的数量

buffer的比较是比较position到limit之间的内容

读取buffer的内容,是从position开始读取的,并不是从0位

反转buffer:buffer.flip();
1 limit = position;
2 position = 0;
3 mark = -1;
flip只能翻转1次,翻转两次将会导致limit也等于0;通常用于read状态切换到write状态,或者write状态切换到read状态

buffer.put(buffer) 会报IllegalArgumentException异常,因为position的移动相矛盾

buffer.slice() 用position和limit之间的内容新生成一个buffer,该buffer的capacity为limit-position的值

charBuffer.wrap(char[], int start, int end) 将会设置positon=start,并将char[]直接传递给charBuffer成为内部char array

从buffer读取数据到数组,必须指定数据的长度:
1 buffer.remaining() < arr.length 读取buffer的position到limit的所有值
2 buffer.remaining() > arr.length 读取buffer中arr.length长度的值,并立即处理,然后再读取buffer中剩余的值

从数组读取数据到buffer:
1 buffer.remaining() > arr.length 读取数组的所有值
2 buffer.remaining() < arr.length 抛出BufferOverflowException

buffer中多字节的数据类型存储的字节顺序没有标准,目前有
1 大端字节顺序(BIG_ENDIAN) ,高位值在低地址(靠左侧),motorola,sun,prow pc的处理器
2 小端字节顺序 (LITTLE_ENDIAN),高位值在高地址(靠右侧),intel处理器
这是由操作系统决定的,可以用ByteOrder.nativeOrder()的返回值:ByteOrder.BIG_ENDIAN 或 ByteOrder.LITTLE_ENDIAN来确定
默认都是BIG_ENDIAN ,这是jvm决定的,所以jvm运行在intel处理器上会有性能隐患
只有ButeBuffer可以修改字节顺序,通过order()方法,除非显式修改,否则创建后永不改变
其他类型的buffer可以转换为ByteBuffer处理

直接缓冲区是IO操作的最好选择。但并非在一开始就一定要创建。
直接缓冲区是调用操作系统的代码分配的,绕开了jvm的堆栈。创建和销毁的代价都比较大。
只有byteBuffer.allocateDirect()才能创建直接缓冲区
allocate() 和 wrap() 的包装方法都创建的是非直接缓冲区(即jvm堆栈内)

ByteBuffer允许通过创建视图来讲byte映射为其他原始数据类型,使用asLongBuffer()等方法

ByteBuffer byteBuffer = ByteBuffer.allocate(7).order(ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer();
charBuffer只是一个view,只是为了方便操作,本质上数据依旧是存放在byteBuffer中的

ByteBuffer的getInt等方法是获取position到limit中的byte并转换为对应的int等数据类型
注意,不同的字节顺序,取出的数值是不同的

java中的byte都是有符号的
获取及存放无符号整数需要自己写一个工具类:
如byte型:
buffer.put( (byte) (value & 0xff) ); 保存value的低8位的值
(short)(buffer.get() & 0xff) 取
short型:
buffer.putShort((short)(value & 0xffff));
(int)(buffer.getShort() & 0xffff);
int型:
buffer.putInt((int)(value & 0xffffffffL));
(long)(buffer.getInt() & 0xffffffffL);