【JAVA】【NIO】4、Java NIO Buffer

Java NIO的Buffer用于和channel进行交互。
buffer本质上是一个内存块,你可以写数据,然后读取出来。
这个内存块是通过NIO的Buffer对象进行包装的,该对象提供了一系列的方法,使得对内存块的访问更加容易了。

基本的Buffer使用

使用Buffer读写数据一般有如下4步:
1、将数据写入 Buffer
2、调用buffer.flip()方法
3、从Buffer中读出数据
4、调用buffer.clear()方法或buffer.compact()方法

当你将数据写入buffer,它会记录你写入了多少数据。一旦你去读数据的时候,你需要反转buffer,通过flip方法,将buffer从写模式转为读模式。在读模式中,buffer允许你读取所有写进去的数据。

一旦你读取了所有的数据,你需要清除buffer,让它再一次为写做好准备,有两种方式:clear()或compact()。clear清除了整个buffer,compact仅仅清除你已经读过的数据。其它未读数据将被移动到buffer的头部,现在写入的数据就会在未读的数据之后。

实例:
这里写图片描述
注意代码中flip,clear等的调用顺序

Buffer的capacity,position和limit

Buffer有三个属性,如上所示
position和limit依赖于Buffer是在读模式还是写模式。Capacity无关模式,总是相同的。
看一张图
这里写图片描述

Capacity

Buffer有固定的大小,叫做capacity,又可以写capacity个字节类型,长整型,字符型等数据,写入buffer。一旦buffer满了,在写入数据之前,你需要置空它(读或者清除)。

Position

当你把数据写入Buffer,就会写到了某个position。position初始为0。当数据写入了,position就会指向写一个插入数据的位置。position最大值为capacity-1。
当你从Buffer中读数据,你也是从某个position开始读。当你flip一个缓冲区从写模式到读模式,position就被重置为0了。读数据的时候,position也会一直移动,指向下一个读的位置。

Limit

在写模式中,limit代表你可以写入多少数据,等于buffer的capacity。
当你flip为写模式的时候,limit代表你可以读出多少数据,因此当flip为读模式,limit被设置为写模式中的position。换句话说,你可以读取写入过的所有数据。

Buffer Types

Java NIO中提供如下Buffer类型:
·ByteBuffer
·MappedByteBuffer
·CharBuffer
·DoubleBuffer
·FloatBuffer
·IntBuffer
·LongBuffer
·ShortBuffer
这些Buffer类型代表不同的数据类型。MappedByteBuffer在后续章节会说。

Allocating a Buffer

为了获取一个Buffer对象,你必须首先分配一块空间。每一个Buffer类都有一个allocate方法。

ByteBuffer buf = ByteBuffer.allocate(48);

CharBuffer buf = CharBuffer.allocate(1024);

Writing Data to a Buffer

写数据到buffer有两种方式:
1、从channel写数据到buffer
2、通过buffer的put方法给自己写数据

int bytesRead = inChannel.read(buf); //read into buffer.

buf.put(127);

flip()

flip方法将缓冲区从写模式转成读模式。调用flip方法将position设置为0,将limit设置为position刚刚之前的位置。
换言之,position现在是读的位置,limit是读的最多限制。
如下图所示:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

Reading Data from a Buffer

同样两种方式可以从buffer中读数据:
1、将数据从buffer中读到channel中
2、通过get方法从自己读

//read from buffer into channel.
int bytesWritten = inChannel.write(buf);

byte aByte = buf.get();

rewind()

该方法设置position为0,所以你可以重新读buffer中的所有数据了。limit保持不变,仍然表示可以从buffer中读取多少数据。
如下图所示:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

clear() and compact()

一旦你读完了buffer的数据,你必须再次将buffer准备好写,通过clear或者compact方法。
clear方法将position设置为0,limit设置为capacity。换言之,buffer清理了,buffer中数据并未清除,只是标记告诉你从哪开始写数据。

如果有任何未读的数据,当你调用clear方法,数据将被忽略。无法找回。

如果仍然有数据未读,但是你想稍后再读取,你可以调用compact而不是clear。

compact方法将所有未读数据移动到buffer的头部,设置position未未读数据的最后一个位置,limit=capacity。现在buffer准备写,但是未读数据不会被重写。

mark() and reset()

可以通过mark方法去标记一个buffer中position,稍后你可以通过reset方法将position设置你刚刚标记的位置。

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

equals() and compareTo()

比较两个buffer是否相等。

equals()

两个buffer如果相等,满足如下条件:
1、它们具有相同的元素类型,
2、它们具有相同数量的剩余元素,并且
3、两个剩余元素序列(与它们的起始位置无关)逐点相同。

比较的是buffer剩余的内容。

compareTo()

该方法比较buffer的剩余元素,满足如下条件,表示一个buffer小于另一个buffer
1、第一个不相等的元素小于另一个buffer中对应的元素
2、所有元素相等,但是第一个buffer比第二个buffer先消耗完(第一个buffer元素更少)
比较两个字节缓冲区的方法是按字典顺序比较它们的剩余元素序列,而不考虑每个序列在其对应缓冲区中的起始位置。

以上解释比较晦涩,很难懂,看个例子吧

ByteBuffer b1 = ByteBuffer.allocate(6);
ByteBuffer b2 = ByteBuffer.allocate(6);
byte[] byte1 = new byte[]{1,3};
byte[] byte2 = new byte[]{1,2};
b1.put(byte1);
b2.put(byte2);
System.out.println(b1.equals(b2));
System.out.println(b1.compareTo(b2));

true
0
虽然byte1和byte2内容不同,但是b1,b2剩余的内容相同,类型也相同,所以equals=true,相等了所以compareTo=0

读者请自行实践吧!!

下一节:【JAVA】【NIO】5、Java NIO Scatter / Gather

展开阅读全文

没有更多推荐了,返回首页