从NIO到netty(2) Buffer和Channel

Buffer本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法

IntBuffer buffer = IntBuffer.allocate(10);
for (int i =0;i 
  

上述代码是一段简单的buffer的用法

IntBuffer#allocate会在java 堆上分配一块内存。注意是堆上,NIO还有堆外内存,这个后续讲

public static IntBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapIntBuffer(capacity, capacity);
}

下面就buffer得三个重要属性做下介绍

  • capacity
  • position
  • limit

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

capacity

作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position

当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit

在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)

写数据到Buffer有两种方式:

  • 从Channel写到Buffer。
  • 通过Buffer的put()方法写到Buffer里。

从Channel写到Buffer的例子

int byteRead = channel.read(buf);

通过put方法写Buffer的例子:

buf.put(127)

 

buffer#flip()方法
public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

可以看到就是将limit位置至于postion位置,然后将position至于0。flip方法用于buffer从读写状态的切换

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

  1. 从Buffer读取数据到Channel。
  2. 使用get()方法从Buffer中读取数据。

从Buffer读取数据到Channel的例子:

int bytesWritten = channel.write(buf)

byte byte =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还可以自己指定position和limit的位置。

lock()方法

RandomAccessFile randomAccessFile  = new RandomAccessFile("/Users/ace/Downloads/zz/qlexpress-demo/netty/收案中心证据.txt","rw");
FileChannel fileChannl = randomAccessFile.getChannel();
//3-6位被锁定为共享锁,读并发可以,写排他
FileLock fileLock = fileChannl.lock(3,6,true);

---------------------------

几个特殊的Buffer

MappedByteBuffer

是直接操作内存的一段buffer

mappedByteBuffer.put(3,(byte)'4');会直接调用DirectByteBuffer#put方法
public ByteBuffer put(int i, byte x) {

    unsafe.putByte(ix(checkIndex(i)), ((x)));
    return this;
}

关于DirectByteBuffer我会在零拷贝那一节讲述

ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();

readOnlyBuffer就是一个只读buffer

如果调用其put方法,就会抛异常

底层是一个HeapByteBufferR

 

你可能感兴趣的:(java,框架)