Java NIO之缓冲区Buffer

时间:2021-12-04 15:55:38

Java NIO的核心部件:

Buffer

Channel

Selector

Buffer

是一个数组,但具有内部状态。如下4个索引:

  • capacity:总容量
  • position:下一个要读取/写入的元素索引
  • limit:限制,第一个不能读取/写入的元素索引
  • mark:位置标记,重置position
  • //通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position//
  • 0 <= mark <= position <= limit <= capacity

用例:

初始状态:

Java NIO之缓冲区Buffer

初始如上图,添加数据:put()方法会改变position的值,但put(int,object)不会改变

buffer.put((byte) H).put((byte) e).put((byte) l).put((byte) l).put((byte) o);

Java NIO之缓冲区Buffer

在上图的基础上进行flip()操作,则会进入下面的状态:

Java NIO之缓冲区Buffer

flip:将缓冲区准备为数据传出状态,即limit=position,position=0

在上图基础上,进行get操作,position会后移,知道position=limit,如下图:

Java NIO之缓冲区Buffer

在上图基础上,进行rewind()的操作,position为0,limit不变,如下图,如需多次读取缓冲区数据,可以在两次读取之间使用rewind()。

Java NIO之缓冲区Buffer

假设新的状态如下图:

Java NIO之缓冲区Buffer

在新状态下进行compact()操作,进入下面状态

Java NIO之缓冲区Buffer

在新状态下进行clear()操作,返回到初始状态,即position=0,limit=capacity

Java NIO之缓冲区Buffer

Buffer的类型:

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

Buffer的分配:工厂方法

1、allocate

//申请48字节

ByteBuffer buf = ByteBuffer.allocate(48);

//申请1024字符

CharBuffer buf = CharBuffer.allocate(1024);

2、wrap,包装一个已有的数组

char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);

注意,这样的方式创建的Buffer,将不会在堆上创建新的数组,而是直接利用myArray做backing store,这意味着任何对myArray或者buffer的修改都将影响到buffer或者myArray。

3、复制Buffer:“浅拷贝”

  • a)通过duplicate()方法将返回一个新创建的buffer,这个新buffer与原来的Buffer共享数据,一样的capacity,但是有自己的position、limit和mark属性。
  • b)通过asReadOnlyBuffer()方法复制的buffer与duplicate()类似,是只读的,不能调用put。
  • c)slice()方法,故名思议,类似切割一个Buffer出来,与duplicate类似,但是它将从原来Buffer的当前position开始,并且capacity等于原来Buffer的剩余元素数目,也就是(limit-position)。

向Buffer写数据

从channel写入到Buffer

int bytesRead = inChannel.read(buf);

通过Buffer的put方法写入

buf.put(127);

相对位置:在position之后写入数据,并改变position

put(byte b);

put(byte[] src);

put(byte[] src, int offset, int length);

put(ByteBuffer src);

绝对位置:提供写入的位置,并不改变position值。

put(int index, byte b);

从Buffer读数据

从channel读出数据

int bytesWritten = inChannel.write(buf);

通过Buffer的get方法

相对位置

get()

get(byte[] dst);

get(byte[] dst, int offset, int length);

绝对位置

get(int index);