数据在网络中传输,必然回遇到读写问题....
2.比较NIO与IO
3.案例演示
3.1.缓冲区演示
package com.wfd360.nio; import org.junit.Test; import java.nio.ByteBuffer; public class BufferDemo { /** * 缓冲区(Buffer) * Buffer在Java NIO 中负责数据的存取,缓冲区就是数组,用于存储不同数据类型的数据。 * <p> * 缓冲区类型 * 根据数据类型的不同(boolean除外),提供了相应类型的缓冲区。 * <p> * ByteBuffer * CharBuffer * ShortBuffer * IntBuffer * LongBuffer * FloatBuffer * DoubleBuffer * 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区。 * ByteBuffer最为常用 * ———————————————— * 缓冲区存取数据的两个核心方法 * put():存入数据到缓冲区中 * flip():切换到读取数据的模式 * get():获取缓冲区中的数据 * rewind():重复读,使position归0 * clear():清空缓冲区,但是缓冲区中的数据依然存在,只是处于一种“被遗忘“的状态。只是不知道位置界限等,读取会有困难。 * mark():标记。mark会记录当前的position,limit,capacity * reset():position,limit,capacity恢复到mark记录的位置 * ------------------- * 缓冲区的四个核心属性 * capacity: 容量,表示缓冲区中最大存储数据的容量,一但声明不能改变。(因为底层是数组,数组一但被创建就不能被改变) * limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写) * position: 位置,表示缓冲区中正在操作数据的位置 * position <= limit <= capacity * mark:标记,表示记录当前position的位置,可以通过reset()恢复到mark的位置。 * ——————————————— */ @Test public void test1() { //1.allocate():分配缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(128); //2.当前缓存区当前属性 System.out.println("-----allocate(128)-------"); print(byteBuffer); //3.放入数据 String put = "123456"; byteBuffer.put(put.getBytes()); System.out.println("-----put()-------"); print(byteBuffer); //4.flip():切换到读取数据的模式 byteBuffer.flip(); System.out.println("-----flip()-------"); print(byteBuffer); //5.读取数据 byte[] bytes = new byte[byteBuffer.limit()]; byteBuffer.get(bytes); System.out.println("读到的数据:" + new String(bytes)); System.out.println("-----get()-------"); print(byteBuffer); //6.rewind():重复读,使position归0 byteBuffer.rewind(); System.out.println("-----rewind()-------"); print(byteBuffer); //7.clear():清空缓冲区,但是缓冲区中的数据依然存在,只是处于一种“被遗忘“的状态。只是不知道位置界限等,读取会有困难 byteBuffer.clear(); System.out.println("-----clear()-------"); print(byteBuffer); //8.清理后仍然可以读取 char aChar = byteBuffer.getChar(); System.out.println("aChar=" + aChar); System.out.println("---清理后读取--getChar()-------"); print(byteBuffer); } /** * 演示 * mark:标记,表示记录当前position的位置,可以通过reset()恢复到mark的位置。 */ @Test public void test2() { ByteBuffer buffer = ByteBuffer.allocate(128); buffer.put("123".getBytes()); System.out.println("-----put()--1-----"); print(buffer); //标记位置 buffer.mark(); System.out.println("-----mark()-------"); print(buffer); //继续放入 buffer.put("456".getBytes()); System.out.println("-----put()--2-----"); print(buffer); //返回到标记处 buffer.reset(); System.out.println("-----reset()-------"); print(buffer); } /** * 直接缓冲区与非直接缓冲区 * 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中。在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容),缓冲区的内容驻留在JVM内,因此销毁容易,但是占用JVM内存开销,处理过程中有复制操作。 * 非直接缓冲区的写入步骤: * 创建一个临时的ByteBuffer对象。 * 将非直接缓冲区的内容复制到临时缓冲中。 * 使用临时缓冲区执行低层次I/O操作。 * 临时缓冲区对象离开作用域,并最终成为被回收的无用数据。 * ———————————————— * 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率。 * 直接缓冲区在JVM内存外开辟内存,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容),缓冲区的内容驻留在物理内存内,会少一次复制过程,如果需要循环使用缓冲区,用直接缓冲区可以很大地提高性能。虽然直接缓冲区使JVM可以进行高效的I/O操作,但它使用的内存是操作系统分配的,绕过了JVM堆栈,建立和销毁比堆栈上的缓冲区要更大的开销 * ———————————————— */ @Test public void test3() { //直接缓冲区 ByteBuffer buffer = ByteBuffer.allocateDirect(128); System.out.println(buffer.isDirect()); //非直接缓冲区 ByteBuffer buffer2 = ByteBuffer.allocate(128); System.out.println(buffer2.isDirect()); } /** * // Invariants: mark <= position <= limit <= capacity * private int mark = -1; * private int position = 0; * private int limit; * private int capacity; * * @param byteBuffer */ public void print(ByteBuffer byteBuffer) { System.out.println("capacity=" + byteBuffer.capacity()); System.out.println("limit=" + byteBuffer.limit()); System.out.println("position=" + byteBuffer.position()); } }