在新的IO中 所有数据的必须通过Channel传输 发送到Channel中的所有对象都必须先放入Buffer中 读取Channel中的对象也要先放入Buffer中
一个Buffer对象是固定数量的数据的容器 作用是一个存储器或分段运输区 在这里数据可被存储并在之后用于检索
对于每个非布尔原始数据类型都有一个缓冲区类
缓冲区倾向于处理字节
缓冲区是一个数组 可以理解成一个容器
缓冲区的属性:
1.容量(Capacity)
能够容纳的数据元素的最大数量 缓冲区创建时被设定 之后不能被修改
2.上限(Limit)
第一个不能被读写的元素 位于limit后的数据不能读写
3.位置(Position)
下一个被读写的元素的索引 position的值恰好为读到了多少数据 新建一个Buffer对象 position为0 读取了2个 position为2 指向Buffer中第3个
4.标记(Mark)
标记位置 调用mark()方法 mark=position reset() position=mark 标记在设定前是undefined
属性之间遵循的关系
0<=mark<=position<=limit<=capacity
Buffer的作用用于装入数据和输出数据
put()和get()
所有缓冲区都是可读的 但不是都是可写的
每个缓存区可以通过执行isReadOnly()来标示是否允许缓存区的内容被修改
对只读缓存区的修改会产生ReadOnlyBufferException
get和put的位置可以是相对(不带索引的)和绝对的
相对调用:
put()过多会导致位置超出上界 会抛出BufferOverflowException异常
get() 位置不小于上界 就会抛出BufferUnderflowException异常
绝对存取不会影响缓冲区的位置属性 但如果索引超出范围(负数或不小于上界) 会抛出IndexOutOfBoundsException异常
flip() = buffer.limit(buffer.position()).position(0) mark=-1
clear() 将缓存区重置为空状态 但它并没有改变缓存区中的任何数据元素 limit=capacity position=0 (恢复到最初状态) mark=-1
rewind() position=0 mark=-1
compact():
将缓冲区的当前位置和界限之间的字节(如果有)复制到缓冲区的开始处
即将索引 p = position() 处的字节复制到索引 0 处 将索引 p + 1 处的字节复制到索引 1 处
依此类推直到将索引 limit() - 1 处的字节复制到索引 n = limit() - 1 - p 处
然后将缓冲区的位置设置为 n+1 并将其界限设置为其容量
如果已定义了标记 则丢弃它
mark()和reset():
mark():设置Buffer的mark位置 只能在0到position之间做mark返回Buffer
reset() 将位置设置为mark所在的索引 position=mark
hasRemaining()和remaining()
hasRemaining:判断positio和limit之间是否有元素
remaining:返回positio和limit之间元素的个数
rewind():position设置为0 取消mark的设置
缓存区的比较:
比较方法中"剩余"的理解:
两者都不允许比较不同类型的Buffer
缓冲区的创建:
以CharBuffer为例:
1.CharBuffer charBuffer = CharBuffer.allocate(100); // 创建100个char容量的CharBuffer
2.char[] charArray = new char[100];
CharBuffer charBuffer = CharBuffer.wrap(charArray);
注意:数据元素会放在charArray中 这意味着通过put()函数造成的对缓冲区的改动会直接影响这个数组 对这个数组的任何
改动也会对这个缓冲区对象可见
CharBuffer charBuffer = CharBuffer.wrap(charArray,12,42); // 创建一个position=12 limit=42+12=54 容量为charArray.length的缓冲区
allocate()和wrap()创建的缓冲区都是间接缓冲区 间接缓冲区使用备份数组
如果hasArray返回false 不要使用array()或arrayOffset函数 不然会抛出UnsupportedOperationException异常
案例:
package com.tony.app;
import java.nio.CharBuffer;
public class CharBufferDemo {
public static void main(String[] args) {
// 创建CharBuffer
CharBuffer charBuffer = CharBuffer.allocate(10);
System.out.println("capacity:" + charBuffer.capacity());
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
// 存放数据
charBuffer.put("Hello");
System.out.println("position:" + charBuffer.position());
charBuffer.flip();
System.out.println("执行flip之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
// 获取数据
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println("获取三个数据之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
charBuffer.clear();
System.out.println("执行clear之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
}
}
输出结果:
capacity:10
limit:10
position:0
position:5
执行flip之后
limit:5
position:0
H
e
l
获取三个数据之后
limit:5
position:3
执行clear之后
limit:10
position:0
package com.tony.app;
import java.nio.CharBuffer;
public class CharBufferDemo {
public static void main(String[] args) {
// 创建CharBuffer
CharBuffer charBuffer = CharBuffer.allocate(10);
System.out.println("capacity:" + charBuffer.capacity());
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
// 存放数据
charBuffer.put("Hello");
System.out.println("position:" + charBuffer.position());
charBuffer.flip();
System.out.println("执行flip之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
// 获取数据
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println("获取三个数据之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
charBuffer.compact();
System.out.println("执行compact之后");
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println(charBuffer.get());
System.out.println(charBuffer.get(0));
System.out.println(charBuffer.get(1));
}
}
输出结果:
capacity:10
limit:10
position:0
position:5
执行flip之后
limit:5
position:0
H
e
l
获取三个数据之后
limit:5
position:3
执行compact之后
limit:10
position:2
l
l
o
l
o
缓冲区的复制:
共享的理解:两个缓冲区中数据相同 容量相同 但每个缓冲区拥有各自的position limit mark 一个缓冲区内的数据元素的改变会反映在另外一个缓冲区上
如果原始的缓冲区为只读或为直接缓冲区 新的缓冲区将继承这些属性
复制一个缓冲区会创建一个新的Buffer对象 但不复制数据 共享数据
分割缓冲区:
slice()创建一个从原缓冲区的当前位置开始的新缓冲区 并且其容量是原始缓冲区的剩余元素容量(limit-position)
新的缓冲区与原始缓冲区共享一段数据元素子序列 新的缓冲区也会继承只读和直接的属性
subSequence()不是真正意义的分割 只是改变了position和limit
package com.tony.app; import java.nio.CharBuffer; public class CharBufferDemo { public static void main(String[] args) { // 创建CharBuffer CharBuffer charBuffer = CharBuffer.allocate(10); System.out.println("capacity:" + charBuffer.capacity()); System.out.println("limit:" + charBuffer.limit()); System.out.println("position:" + charBuffer.position()); // 存放数据 charBuffer.put("Hello"); System.out.println("position:" + charBuffer.position()); System.out.println("limit:" + charBuffer.limit()); // 分割缓存区 CharBuffer charBuffer_sub = charBuffer.slice(); System.out.println("新的缓冲区"); System.out.println("capacity:" + charBuffer_sub.capacity()); System.out.println("limit:" + charBuffer_sub.limit()); System.out.println("position:" + charBuffer_sub.position()); // 再次存放数据到charBuffer charBuffer.put("tony"); // 查看charBuffer_sub中的数据 System.out.println(charBuffer_sub.get()); System.out.println(charBuffer_sub.get()); System.out.println(charBuffer_sub.get()); System.out.println(charBuffer_sub.get()); // subSequence分割缓存区 charBuffer.clear(); CharBuffer charBuffer_subSequence = charBuffer.subSequence(6, 8); System.out.println("capacity:" + charBuffer_subSequence.capacity()); System.out.println("limit:" + charBuffer_subSequence.limit()); System.out.println("position:" + charBuffer_subSequence.position()); } }
输出结果:
capacity:10 limit:10 position:0 position:5 limit:10 新的缓冲区 capacity:5 limit:5 position:0 t o n y capacity:10 limit:8 position:6
字节缓冲区(ByteBuffer):
所有的基本数据类型都有相应的缓冲区类 boolean除外 但字节缓冲区有独特之处
字节是操作系统和I/O设备 挡在JVM和OS间传递数据时 将其他的数据类型拆分成字节是必要的
多字节数值被存储在内存中的方式一般被称为endian-ness(字节顺序)
字节顺序:
大端和小端
大端:如果数字数值的最高字节位于低位地址 那么系统就是大端字节顺序
小端:大端反之
字节顺序很少由软件设计者决定 它通常取决于硬件设计
Intel处理器使用小端顺序
IP协议使用大端的网路字节顺序
在NIO中 字节顺序由ByteOrder类封装
toString返回大端或小端
每个Buffer类通过order方法返回当前字节的顺序
直接缓冲区:
视图缓冲区:
ByteBuffer类允许创建视图来讲byte类型Buffer映射为其它的原始数据类型
asLongBuffer():将Byte转化为long类型数据来存储的视图缓冲区
package com.tony.app; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; public class CharBufferDemo { public static void main(String[] args) throws UnsupportedEncodingException { ByteBuffer byteBuffer = ByteBuffer.allocate(10); byteBuffer.order(ByteOrder.BIG_ENDIAN); CharBuffer charBuffer = byteBuffer.asCharBuffer(); byteBuffer.put("tony".getBytes()); System.out.println("capacity:" + byteBuffer.capacity()); System.out.println("limit:" + byteBuffer.limit()); System.out.println("position:" + byteBuffer.position()); System.out.println("ByteBuffer==>CharBuffer"); System.out.println("capacity:" + charBuffer.capacity()); System.out.println("limit:" + charBuffer.limit()); System.out.println("position:" + charBuffer.position()); } }
capacity:10
limit:10
position:4
ByteBuffer==>CharBuffer
capacity:5
limit:5
position:0
package com.tony.app;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
public class CharBufferDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
ByteBuffer byteBuffer = ByteBuffer.allocate(10); byteBuffer.order(ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer();
byteBuffer.putChar('t');
byteBuffer.putChar('o');
byteBuffer.putChar('n');
byteBuffer.putChar('y');
System.out.println("ByteBuffer==>CharBuffer");
System.out.println("capacity:" + charBuffer.capacity());
System.out.println("limit:" + charBuffer.limit());
System.out.println("position:" + charBuffer.position());
System.out.println("CharBuffer:" + charBuffer.toString());
}
}
ByteBuffer==>CharBuffer
capacity:5
limit:5
position:0
CharBuffer:tony
存取无符号数据
内存映射缓冲区(MappedByteBuffer)
P54-55