Java nio 之 Buffer反转flip


JavaDoc上的关于Buffer#flip()的描述是:

  • flip() 使缓冲区为一系列新的通道写入或相对获取 操作做好准备:它将限制设置为当前位置,然后将位置设置为 0。 

先吐槽下JavaDoc对于 缓冲区的限制 limit 的描述,limit是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负,并且不能大于其容量。 恕在下功底过差,这个描述理解了半天,我个人更倾向于把 limit 叫着上限,意指 缓冲区中现存元素的计数,或者缓冲区有效内容的末端,这样结合上述描述就很容易理解这个limit的含义了。


继续说flip方法,下面整理至《Java NIO》一书:

当我们已经写满了缓冲区,现在我们必须准备将其清空。我们想把这个缓冲区传递给一个通道,以使内容能被全部写出。但如果通道现在在缓冲区上执行get(),那么它将从我们刚刚插入的有用数据之外取出未定义数据。如果我们将位置值重新设为0,通道就会从正确位置开始获取,但是它是怎样知道何时到达我们所插入数据末端的呢?这就是上界属性被引入的目的。上界属性指明了缓冲区有效内容的末端。我们需要将上界属性设置为当前位置,然后将位置重置为0。我们可以人工用下面的代码实现:

 buffer.limit(buffer.position()).position(0);

但这种从填充到释放状态的缓冲区翻转是API设计者预先设计好的,他们为我们提供了一个非常便利的函数: Buffer.flip(); 

flip()函数将一个能够继续添加数据元素的填充状态的缓冲区翻转成一个准备读出元素的释放状态。

rewind()函数与flip()相似,但不影响上界属性。它只是将位置值设回0。您可以使用rewind()后退,重读已经被翻转的缓冲区中的数据。

  • rewind()使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为 0。


ByteBuffer中,flip方法常结合compact方法进行write to channel 操作,以防写入不完整:

        // Make sure that the buffer is fully drained
        while (src.read(buffer) != -1 || buffer.hasRemaining())
        {
            buffer.flip();
            dest.write(buffer);
            // If partial transfer, shift remainder down
            // If buffer is empty, same as doing clear( )
            buffer.compact(); // In case of partial write
        }

compact()在javadoc上解释很清楚了,这里直接以例子的形式说明让人更容易在感官上理解。

被部分释放的缓冲区:

执行buffer.compact() 压缩buffer后:

  

数据元素2-5被复制到0-3位置。位置4和5不受影响,但现在正在或已经超出了当前位置,因此是“死的”。它们可以被之后的put()调用重写。还要注意的是,位置已经被设为被复制的数据元素的数目。也就是说,缓冲区现在被定位在缓冲区中最后一个“存活”元素后插入数据的位置。最后,上界属性被设置为容量的值,因此缓冲区可以被再次填满调用compact()的作用是丢弃已经释放的数据,保留未释放的数据,并使缓冲区对重新填充容量准备就绪。

compact后调用flip进行反转,position变为0,limit变为4,这样就能继续write 0-3位置数据。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值