Buffer的基本使用
利用buffer读写数据主要走下面4小步骤
1)数据写入到buffer中
2)调用buffer.flip()
3)从buffer中读取数据
4)调用buffer.clear()或者buffer.compact()
当你写数据到buffer中时,buffer会记住你已经写入到多少数据了。一旦你需要从buffer中读取数据了,你需要调用它的flip()方法,将写模式切换成读模式,在读模式下,buffer允许你读取所有写在它里面的数据。
注意:读原文的时候,读写感觉到有点绕,特别是channel.read(buffer), 虽然是个read方法,但是此时buffer是出于写模式下的,因为Channel将数据写入到buffer中,所以读写模式是对于buffer来说的。数据放入buffer中就是写,数据从buffer中出去就是读。
一旦你从buffer中读完数据了,你需要清空buffer,准备好下次写数据进去。清空可以通过clear方法或者compact方法来实现。clear方法可以清空整个buffer。compact方法会清空你已经读取过的数据,任何未读的数据会被移动到buffer的开头处,后面再像buffer写数据的时候,数据会继续追加在前面的数据后面。(恩,有点像拿吸管喝一杯可乐,管子插到杯子底部,你吸了一部分可乐,剩下的可乐会自动向下移动到某个位置,当你添加可乐的时候,所加的可乐也是在剩下的可乐的移动后的位置上追加的,不是太恰当,是这么个意思==!)
下面是一个小例子,几个操作都在里面
Buffer 中的Capacity, Position and Limit
一个buffer本质上就是一块内存,你可以往这这个内存写数据,再读取。JAVA NIO BUFFER对象将这块内存封装起来,对外暴露一些api接口,方便使用者操作这块内存。
为了理解buffer,你得熟悉三个概念Capacity, Position and Limit。其中Position和Limit的具体含义取决于buffer是处在读还是写模式下,Capacity则不管是读还是写,总是表示buffer的容量。
下面是一个图解:
Capacity
在内存块中,一个buffer有一个确定的大小,成为capacity。你总共只能写capacity个bytes,longs,chars等到buffer中,多一个也写不进去。一旦buffer满了,一旦buffer满了,在你下次写数据之前,你需要清空它(从buffer中读或者clear)。
Position
写模式下,是从buffer中某一个确定的position开始写的。position初始化为0。当一个byte或者long型的数据写入到buffer中的时候,postion的位置就递增一个,你可以理解为指针,指向下一个位置。因为buffer最大容量为capacity,0代表第一个位置,所以position的最大值必然为capacity-1.
读模式下,也是从某一个确定的position开始的,当你调用buffer.flip()方法的时候,会从写模式切换到读模式,position会被设置为0。当你从buffer的position位置开始读的时候,每读取一个,position的位置就会加1.
Limit
在写模式下,buffer的limit就是指你可以写limit个数据到buffer中。在写模式下,limit就等于capacity。
当你调用flip方法切换到读模式下,limit就意味着你可以读取多少个数据。当调用flip方法的时候,limit会被设置为写模式下的position。换句话说,你前面的写模式下写了多少个数据,后面才能读取多少个。
Buffer 的实现类型
主要有以下几种:
ByteBuffer、MappedByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer
构造 buffer
通过调用allocate方法来构造一个buffer对象,下面的这个方法就是构造了一个capacity等于48的大小的bytes。
ByteBuffer buf = ByteBuffer.allocate(48);
写数据到buffer中
1)通过channel的read方式
int bytesRead = inChannel.read(buffer); //read into buffer.
2)通过buffer自身的put方式
buffer.put(127);
还有其他的put方法,本质都一样
从buffer中读数据
也有两种方式:
1)从buffer中读取数据到channel中
int bytesWritten = inChannel.write(buf);
2)buffer自身的get方式
byte aByte = buf.get();
rewind()
rewind是倒回的意思,当你读了一部分数据之后,调用此方法之后,postion会变为0,也就是说又从头开始读。
clear() and compact()
一旦你从buffer读完数据之后,为了下次能继续往里面写数据,你必须调用clear方法或者compact方法。
如果你调用clear方法,position会被设置为0,limit会被设置为capacity。也即是说切换到写模式了。
当你还未读完buffer中的数据的时候,你调用clear方法的话,那些未读的数据也会被“遗忘”掉。如果说还有未读完的数据,这个时候你想开始写操作,然后在读取数据的时候回,那些之前未读的数据你还想继续读取,请调用compact方法。
mark() and reset()
ou can mark a given position in aBufferby calling theBuffer.mark()method. You can then later reset the position back to the marked position by calling theBuffer.reset()method. Here is an example:
mark方法就是标记buffer当前的position,然后你继续读取buff,position位置会发生变化,此时当你调用reset方法的时候,position会重新回到之前标记的postion。
源码中很容易看出来