2.NIO通道与缓冲区

2018-05-13  本文已影响0人  xialedoucaicai

通道就是IO源与目标之间的连接,类似IO中的流,不过通道本身并不能直接访问数据,就像铁路一样,负责传输。
缓冲区就是装载源或目标的容器,类似IO中的byte[],直接操作数据(将文件读入缓冲区,将缓冲区中的数据写入文件),就像火车一样,负责装货。
一句话:通道用于传输,缓冲区用于存取。

除了Boolean类型,其他基本类型都有对应的缓冲区,我们常用的是ByteBuffer。Buffer的重要属性:

private int mark = -1;//标记position的位置,结合reset让position回到当时mark的位置

private int position = 0;// 当前操作数据的位置

private int limit; //可操作数据量

private int capacity;// 缓冲区最大容量

四者的关系:
mark <= position <= limit <= capacity
来张图可能更好理解:


buffer的属性

话不多说,直接上例子:

public void testBuffer(){
    String s = "abced";
    //allocate分配指定大小的缓冲区
    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    System.out.println("-------allocate()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    
    //put向缓冲区加入内容
    byteBuffer.put(s.getBytes());
    System.out.println("-------put()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    
    //flip切换成读模式
    byteBuffer.flip();
    System.out.println("-------flip()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    
    //get读取缓冲区
    byte [] dest = new byte [byteBuffer.limit()];
    byteBuffer.get(dest);
    System.out.println("读取到的数据"+new String(dest));
    
    System.out.println("-------get()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    
    //rewind恢复到上次读取初始状态,可以重复读取数据
    byteBuffer.rewind();
    System.out.println("-------rewind()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    
    //clear清空缓冲区,但缓冲区中的数据仍然存在,只是处于被遗忘状态
    byteBuffer.clear();
    System.out.println("-------clear()-----------");
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
    //这里仍然能够读取到
    System.out.println((char)byteBuffer.get());
    System.out.println("position->"+byteBuffer.position());
    System.out.println("limit->"+byteBuffer.limit());
    System.out.println("capacity->"+byteBuffer.capacity());
}

mark()和reset()结合使用:

public void testMark(){
    String s = "abced";
    
    //allocate分配指定大小的缓冲区
    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    //放入数据
    byteBuffer.put(s.getBytes());
    //切换到读
    byteBuffer.flip();
    //读2个字节
    byte dest [] = new byte [2];
    byteBuffer.get(dest,0,2);
    System.out.println(byteBuffer.position());//2
    //进行标记
    byteBuffer.mark();
    //再读2个字节
    byteBuffer.get(dest,0,2);
    System.out.println(byteBuffer.position());//4
    //让position回到上次标记的位置
    byteBuffer.reset();
    System.out.println(byteBuffer.position());//2
    
    //判断缓冲区是否仍有可操作数据
    if(byteBuffer.hasRemaining()){
        //还有多少可操作数据
        System.out.println(byteBuffer.remaining());//3
    }
}

flip()和clear(),应该是操作buffer时候用的最多的。经过测试和分析API(其实看源码可以发现这些方法其实就是在改变buffer的四个属性值),发现如下最佳实践:

  1. buffer写入之后,读取时,需要先执行flip()。注意这里的读取是指读取buffer,读取和写入是相对的,对文件是写入,对buffer就是读取
  2. 复用buffer,再次写入之前,最好先执行clear()方法
    上代码:
public void testFlip(){
    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
    byteBuffer.put("12345".getBytes());
    //写模式切换成读模式
    byteBuffer.flip();
    String s = new String(byteBuffer.array(),0,byteBuffer.limit());
    System.out.println(s);
    
    //复用buffer之前,最好先清空
    byteBuffer.clear();
    byteBuffer.put("6".getBytes());
    byteBuffer.flip();
    System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
}
上一篇 下一篇

猜你喜欢

热点阅读