《Java NIO》学习笔记二 缓冲区(Buffer)

本文介绍了Java NIO中的缓冲区关键属性:capacity、position和limit,详细阐述了它们在读写模式中的作用。讨论了缓冲区的翻转、清除、压缩等操作,以及如何创建和释放缓冲区。此外,还讲解了高效批量移动数据的方法,如get()和put(),并探讨了缓冲区的复制和分割操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、关于缓冲区的四个属性:capacitypositionlimit在读写模式中的说明:

1capacity

缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能被改变。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续往里写数据。

2position

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

②当读取数据时,也是从某个特定位置读。

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

3limit

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

②当切换Buffer读模式时,limit表示你最多能读到多少数据。因此当切换到读模式时,limit会被设置成写模式下的position

 

 

二、缓冲区Buffer类介绍:

1buffer.flip();  //翻转缓冲区

当缓冲去写满后,我们需要把缓冲区的数据传递给一个通道,以使内容能被全部写出。但如果通道直接在缓冲区上执行get()操作, 这是中错误的操作,因为它将从我们刚刚插入的有用数据之外取出未定义数据。因此我们在获取缓冲区数据之前需要调用flip()方法,position定位到0位置;并且将limit设置成之前写模式下的position的值,用来指明指明了缓冲区有效内容的末端。

2、buffer.clear();  //清除整个缓冲区

方法并不改变缓冲区中的数据,它只是将position设置为0,并将limit设置为等于capacity,从而使缓冲区准备好从缓冲区的put操作或信道的读操作接收新的数据

3compact()   //压缩此缓冲区(可选操作)。

compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处将position设置为未读数据的后面位置,因此新写入的数据将放到缓冲区未读数据的后面。limit属性被设置为capacity的值,因此缓冲区可以被再次填满。

 

三、创建缓冲区:

1allocate()

ByteBuffer buffer=ByteBuffer.allocate(256);

创建一个容量为256字节的ByteBuffer,如果发现创建的缓冲区容量太小,唯一的选择就是重新创建一个大小合适的缓冲区.

2wrap()

ByteBuffer buffer=ByteBuffer.wrap(byteArray);  

//通过包装一个已有的数组来创建,通过此方法创建的缓冲区保留了被包装数组内的数据

这段代码构造了一个新的缓冲区对象,但数据元素会存在于数组中。这意味着通过调用put()方法造成的对缓冲区的改动会直接影响这个数组,而且对这个数组的任何改动也会对这个缓冲区对象可见。

上面两种创建缓冲区的区别:

分配操作创建一个缓冲区对象并分配一个私有的空间来储存容量大小的数据元素。

包装操作创建一个缓冲区对象但是不分配任何空间来储存数据元素。它使用您所提供的数组作为存储空间来储存缓冲区中的数据元素。

 

四、缓冲区的释放:

hasRemaining()会在释放缓冲区时告诉您是否已经达到缓冲区的上界。以下是一种将数据元素从缓冲区释放到一个数组的方法

for (int i = 0; buffer.hasRemaining( ), i++) { 

myByteArray [i] = buffer.get( ); 

remaining()方法将告知您从当前位置到上界还剩余的元素数目。您也可以通过下面的循环来释放缓冲区。

int count = buffer.remaining( ); 

for (int i = 0; i < count, i++) { 

myByteArray [i]  = buffer.get( ); 

}

 

五、向缓冲区批量移动数据的高效方法:

get()的批量操作:

public CharBuffer get (char [] dst) 

public CharBuffer get (char [] dst, int offset, int length) 

put()的批量操作:

public final CharBuffer put (char[] src) 

public CharBuffer put (char [] src, int offset, int length) 

public CharBuffer put (CharBuffer src) 

public final CharBuffer put (String src) 

public CharBuffer put (String src, int start, int end)

有两种形式的get( )可供从缓冲区到数组进行的数据复制使用:

第一种形式只将一个数组作为参数,将一个缓冲区释放到给定的数组。

第二种形式使用offsetlength参数来指定目标数组的子区间。

如果缓冲区中的数据不够完全填满数组,您会得到一个异常。这意味着如果您想将一个小型缓冲区传入一个大型数组,您需要明确地指定缓冲区中剩余的数据长度。要将一个缓冲区释放到一个大数组中,要这样做:

int length = buffer.remaining( ); 

buffer.get (bigArrray, 0, length);

当然,还有另外一种情况,那就是缓冲区的数据容量大于数组能容纳的数据容量,可以用下面解决办法:

char [] smallArray = new char [10]; 

while (buffer.hasRemaining( )) { 

int length = Math.min (buffer.remaining( ), smallArray.length); 

buffer.get (smallArray, 0, length); 

processData (smallArray, length);  // Do something useful with the data

Put()的批量操作:

如果缓冲区有足够的空间接受数组中的数据(buffer.remaining()>myArray.length),数据将会被复制到从当前位置开始的缓冲区,并且缓冲区位置会被提前所增加数据元素的数量。

如果缓冲区中没有足够的空间,那么不会有数据被传递,同时抛出一个BufferOverflowException异常。

 

六、复制缓冲区:

public abstract CharBuffer duplicate( ); 

public abstract  CharBuffer asReadOnlyBuffer( ); 

public abstract  CharBuffer slice( );

1duplicate()方法创建了一个与原始缓冲区相似的新缓冲区。两个缓冲区共享数据元素,拥有同样的容量,但每个缓冲区拥有各自的位置,上界和标记属性。对一个缓冲区内的数据元素所做的改变会反映在另外一个缓冲区上。这一副本缓冲区具有与原始缓冲区同样的数据视图。如果原始的缓冲区为只读,或者为直接缓冲区,新的缓冲区将继承这些属性。

2asReadOnlyBuffer()方法来生成一个只读的缓冲区视图。这与duplicate()相同,除了这个新的缓冲区不允许使用put(),并且其isReadOnly()方法将会返回true。对这一只读缓冲区的put()方法的调用尝试会导致抛出ReadOnlyBufferException异常。

3、分割缓冲区与复制相似,但slice()创建一个从原始缓冲区的当前位置开始的新缓冲区,并且其容量是原始缓冲区的剩余元素数量(limit-position)。这个新缓冲区与原始缓冲区共享一段数据元素子序列。分割出来的缓冲区也会继承只读和直接属性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值