美文网首页
NIO(二)—— Buffer缓冲区

NIO(二)—— Buffer缓冲区

作者: 天探女 | 来源:发表于2020-08-19 22:21 被阅读0次

    转载文章: 转载自并发编程网 – ifeve.com

    Buffer缓冲区

    管道Channel将数据写入到缓冲区Buffer,管道Channel从缓冲区Buffer读取数据

    基本使用

    1. 写数据到Buffer
    2. WtoR(写模式切换为读模式).flip()
    3. Buffer读出数据
    4. 清除Buffer.clear() or .compact()

    当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式。在读模式下,可以读取之前写入到buffer的所有数据。

    一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

    读取文件的例子

    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
    FileChannel inChannel = aFile.getChannel();
    
    //为buf分配48byte的空间
    ByteBuffer buf = ByteBuffer.allocate(48);
    
    int bytesRead = inChannel.read(buf); // 通过管道将文件数据写入buf
    while (bytesRead != -1) {
    
      buf.flip();  // 从写模式转换为读模式
    
      while(buf.hasRemaining()){
          System.out.print((char) buf.get()); // 循环读取1byte并打印
      }
    
      buf.clear(); //清空buf,并等待写
      bytesRead = inChannel.read(buf); // 通过管道将文件数据接入buf
    }
    aFile.close();
    

    容量 Capacity

    可以看出,Buffer与系统底层的缓冲区设计是十分相似的
    为buffer设定固定容量Capacity,当Buffer满了,则必须清空或者读取数据才能继续写Buffer

    位置 Position

    可以当做指针

    • 写模式下
      position 表示当前位置,初始为0,当写入一个数据后,指针会移动到下一个可以写的Buffer单元,Position最大值为capacity - 1
    • 读模式下
      从某特定位置开始读。当从写模式切换为读模式时,position置零。当读取一个数据时,指针会移动到下一个可读的单元

    范围 Limit

    • 写模式下
      limit即为Buffer的capacity
    • 读模式下
      limit表示最多能读多少数据,此时limit为写模式下position的值,即为已写数据的数量。

    Buffer操作

    分配空间

    ByteBuffer buf = ByteBuffer.allocate(48); //分配48个byte空间
    

    写数据

    写数据到Buffer有两种方式:

    1. 从Channel写到Buffer的例子
      int bytesRead = inChannel.read(buf); //read into buffer
      
    2. 通过put方法写Buffer的例子:
      buf.put(127);
      

    put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。例如, 写到一个指定的位置,或者把一个字节数组写入到Buffer。

    flip()

    flip()方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
    换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 ,即现在能读取多少个byte、char等。

    读取数据

    从Buffer中读取数据
    从Buffer中读取数据有两种方式:

    1. 从Buffer读取数据到Channel的例子:
      //read from buffer into channel.
      int bytesWritten = inChannel.write(buf);
      
    2. 使用get()方法从Buffer中读取数据的例子
      byte aByte = buf.get();
      

    rewind()

    Buffer.rewind()将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素(byte、char等)。

    clear()与compact()

    一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。

    如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。

    如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。

    如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。

    compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

    mark()与reset()

    通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position。例如:

    buffer.mark();
    //call buffer.get() a couple of times, e.g. during parsing.
    buffer.reset();  //set position back to mark.
    

    这个东西在Netty解码器里解决半包问题用到

    相关文章

      网友评论

          本文标题:NIO(二)—— Buffer缓冲区

          本文链接:https://www.haomeiwen.com/subject/bvvhuhtx.html