“ NIO【Non-blocking IO非阻塞式IO】,可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似,主要分为3部分:Channels and Buffers and Selectors(通道和缓冲区和选择器)今天我们要讲的就是Buffer概述”
听歌时间
01
—
Buffer概述
/**
* Java NIO中的Buffer用于和NIO通道{Channel【FileChannel|SocketChannel】}进行交互,
* 数据是从通道读入缓冲区,从缓冲区写入到通道中的。
* 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。
* 这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
* 用于特定基本类型的数据的缓冲区容器,每个非布尔基本类型都有这个类的一个子类
* ByteBuffer , CharBuffer , DoubleBuffer , FloatBuffer , IntBuffer , LongBuffer , ShortBuffer
* 其中和ByteBuffer相关的子类有3个:
* MappedByteBuffer,HeapByteBuffer,DirectByteBuffer extends MappedByteBuffer
* 是特定原始类型的元素的线性有限序列缓冲区。除了其内容【缓冲区数组】,
* 缓冲区对象还有其它3个基本属性
* 1:capacity:它所包含的元素数量叫缓冲区的容量。缓冲区的容量永远不会为负且永远不会改变
* 2:limit:第一个不能被读/写的元素的索引叫缓冲区的限制。缓冲区的限制永远不大于缓冲区的容量
* 3:position:下一个要读取或写入的元素的索引叫缓冲区的位置。缓冲区的位置永远不会大于其限制。
* Buffer类的每个子类定义了一系列get和put操作:
* 相对的读写操作每次都从当前位置开始读写,并将位置+1
* 绝对的读写操作采用显式的元素索引,并不影响位置
* 无论是相对的还是绝对的读写操作,索引都不能超过【exceeds】其限制
* 标记,位置,极限和容量值满足以下关系:
* 0 <= mark <= position <= limit <= capacity
* 标记和重置、清理,翻转和倒带
* 调用reset方法一定保证mark方法被调用过
* mark方法源码:
* mark = position;return this;
* reset方法源码:
* int m = mark;if (m < 0){throw new InvalidMarkException()};position = m;return this;
* clear方法源码:
* position = 0;limit = capacity;mark = -1;return this;
* flip方法源码:
* limit = position;position = 0;mark = -1;return this;
* rewind方法源码:
* position = 0;mark = -1;return this;
* 读与写操作之间要调用flip方法
* 线程不安全,可以链式调用
* b.flip().position(23).limit(42);
*
*/
02
—
代码演示
import java.nio.ByteBuffer;import java.util.Arrays;public class ByteBufferTest {public static void main(String[] args) {//根据指定的容量创建一个字节缓冲区,两种方式//分配5个字节
ByteBuffer byteBuffer = ByteBuffer.allocate(5);//ByteBuffer.wrap(new byte[5]);// 往 ByteBuffer放入数值
byteBuffer.put((byte)10);
byteBuffer.put((byte)20);//byteBuffer.putInt(1000);//放入一个int占4个字节
System.out.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));
System.out.printf("打印一下是否有字节数组: %s%n",byteBuffer.hasArray());
System.out.printf("打印一下指针位置: %s%n",byteBuffer.position());
System.out.printf("打印一下字节缓冲区容量: %s%n",byteBuffer.capacity());
System.out.printf("打印一下字节缓冲区限制: %s%n",byteBuffer.limit());
System.out.printf("打印一下字节缓冲区从当前位置到限制之间的剩余元素: %s%n",byteBuffer.remaining());
System.out.printf("从当前位置到限制之间是否有剩余元素: %s%n",byteBuffer.hasRemaining());
System.out.printf("是否是直接缓冲区: %s%n",byteBuffer.isDirect());
System.out.printf("该缓冲区是否是只读: %s%n",byteBuffer.isReadOnly());//设置位置和限制
byteBuffer.flip().position(2).limit(4);
System.out.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));//get方法获取的是position+1的索引对应的值
System.out.printf("flip之后获取位置为2的数据: %s%n",byteBuffer.get());
System.out.printf("标记后重置: %s%n",byteBuffer.mark().reset());
byteBuffer.put((byte)60);
System.out.printf("重新获取位置: %s%n",byteBuffer.position());//该方法和flip方法差不多,都用于读写切换,只不过rewind方法前提是limit被合理的设置
byteBuffer.rewind();
System.out.printf("重新获取值: %s%n",byteBuffer.get());//重置为最开始创建的时候,只不过没有清除数据
System.out.printf("重置但不清除数据: %s%n",byteBuffer.clear());//创建一个新的剩余内容子共享缓冲区,【也就是说字节数组是共享的】// 该新的缓冲区是指定缓冲区的剩余部分,修改哪一个另外一个都会同步修改//这两个缓冲区的位置,限制和标记值将是独立的//通过position++加上offset来定位在原数组中的位置
ByteBuffer subByteBuffer = byteBuffer.slice();
subByteBuffer.put((byte)30);
System.out.printf("打印一下子字节数组: %s%n",Arrays.toString(subByteBuffer.array()));//只有调用slice方法,offset才会被设置
System.out.printf("打印一下缓冲区偏移量: %s%n",subByteBuffer.arrayOffset());
System.out.printf("打印一下子指针位置: %s%n",subByteBuffer.position());
System.out.printf("打印一下子字节缓冲区容量: %s%n",subByteBuffer.capacity());
System.err.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));
System.err.printf("打印一下指针位置: %s%n",byteBuffer.position());
System.err.printf("打印一下字节缓冲区容量: %s%n",byteBuffer.capacity());
System.err.printf("打印一下字节缓冲区限制: %s%n",byteBuffer.limit());
byteBuffer.rewind();
System.err.printf("获取: %s%n",byteBuffer.get());
}
}
03
—
MappedByteBuffer概述与联系
直接字节缓冲器,其内容是文件的存储器映射区域。
映射的字节缓冲区是通过FileChannel.map方法创建的。此类扩展了具有特定于内存映射文件区域的操作的ByteBuffer类。
映射字节缓冲区及其表示的文件映射在缓冲区本身被垃圾回收之前保持有效。
映射字节缓冲区的内容可以随时更改,例如,如果该程序或其他映射文件的对应区域的内容被更改。
这种变化是否发生,何时发生,是操作系统依赖的,因此是未指定的。
映射字节缓冲区的全部或部分可能在任何时候变得无法访问,例如映射文件被截断。
访问映射字节缓冲区的不可访问区域的尝试不会更改缓冲区的内容,
并将导致在访问时或稍后的时候抛出未指定的异常。因此,强烈建议您采取适当的预防措施,
以避免该程序或同时运行的程序对映射文件进行操作,但读取或写入文件的内容除外。
映射的字节缓冲区的行为与普通的直接字节缓冲区不同。
04
—
FileChannel
写在最后
总结:今天花了点时间写了关于Buffer的概述,关于实战部分请参考往期精彩文章
>>>往期精彩文章
使用一种全新的方式【java NIO】拆分大电影文件,并合并分割后的文
件为电影文件