欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java NIO 入门(四)Buffer内部原理

程序员文章站 2022-07-13 17:03:06
...
Java NIO 入门(四)Buffer内部原理
guibin.beijing@gmail.com

概述
在这节中,我们将关注NIO的Buffer中两个重要的组件:状态变量和访问方法。
状态变量对于前面提到的“内部计数系统”而言相当重要,每次进行完读写之后,Buffer的状态都随之改变。通过记录和跟踪这些改变,Buffer才可以把Buffer内部的资源管理好。

当你从Channel中读数据时,数据首先放到了Buffer中。在某些情况下,你可以直接把这个Buffer写入另一个Channel中,但是通常情况下,你可能想看看数据内容,这个想法可以通过方法get()实现。相似的,当你想要把原始数据放进Buffer中,你可以使用put()方法。

在这节中,我们将学习NIO中的状态变量和访问方法。每个组件都会涉及到,并且有机会查看具体的使用。然而NIO的内部计数系统起初看起来可能有些复杂,你很快会看到内部计数系统实际上为你做了哪些事情。

状态变量
总共有三个值可以被用来表示在给定的任何时刻Buffer的状态,他们分别是:
  • position
  • limit
  • capacity

这三个变量跟踪了Buffer的状态和Buffer所包含的数据。
接下来我们将逐一检查每个细节,并且也看看为什么这样的设计适合典型的读/写(输入/输出)处理。比如仅仅这个例子,我们假设从一个Channel拷贝数据到另一个Channel。

Position
回忆一下,Buffer实际上也就是个array。当你从Channel中读数据时,你把从Channel中读出来的数据放进底层array,position变量用来跟踪截止目前为止已经写了多少数据。更精确的讲,它指示如果下次写Buffer时数据应该进入array的哪个位置。因此如果已经从Channel中读出了3个字节,Buffer的position会被置为3,指向array中第四个位置。
相似的,如果正在向Channel中写入数据,你需要从Buffer中获取要写的数据,此时position持续的跟踪你已经从Buffer中读取了多少数据。更精确的说,position指示了下一次从Buffer中读取数据时将读入array的哪个元素。因此如果你已经向Channel中写了5个byte,Buffer的position被置为5,指向array中第六个元素。

Limit
在从Buffer中向Channel中写数据时,limit变量指示了还剩多少数据可以读取,在从Channel中读取数据到Buffer中时,limit变量指示了还剩多少空间可供存放数据。
position正常情况下小于或者等于limit。

Capacity
Buffer的Capacity指示Buffer最多能够存储的数据。实际上,它指示了底层array的容量,或者至少是底层array允许使用的空间数量。
Limit永远不会大于capacity。

以实例来观察这三个变量
我们从一个新建的Buffer开始。由于是例子的缘故,我们假设Buffer有一个8字节大小的Capacity。此时Buffer的状态如下所示:
Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

回忆之前所讲的,limit不会大于capacity,在这个例子中,limit和capacity都会被设为8。我们通过在array尾部用箭头指示的方式表示。
Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

此时position设置为0。如果我们从Channel读了一些数据进入Buffer,下一个字节将会被存入位置为0的地方。如果我们从Buffer中写数据进入Channel,Buffer中下一个被读的字节将从位置0取得。position的设置如下图所示:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

因为capacity一旦设置好就不会改变了,之后的讨论我们将暂时忽略capacity。

第一次读操作
现在我们准备好了在我们新建的Buffer上开始读/写操作了。我们开始从Channel中读一些数据进入Buffer,第一次读3个字节。读之前position为0,读完后position从0增长到3,如下所示:
Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

第二次读操作
第二次读操作,我们将再读2个字节从Channel到Buffer中,这两个字节存储的位置从之前的position即3开始,读完后position增加了2变为5。如下图:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

Flip操作
到目前位置,我们结束了从Channel中读的操作,现在开始将数据写入输出Channel中。在做写操作之前,我们必须调用一次flip()方法,这个方法做了两件重要的事情:
1. 将limit设置到当前的position处。
2. 设置position为0。
上幅图展示了在执行flip之前的Buffer,下面这幅图展示了执行了flip() 之后的Buffer:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

现在我们已经准备好了把数据从Buffer中写到Channel中。Position已经设置为0,意思是说我们将获得的下一个字节为位置为0的字节,limit已经设置到了之前的position处,意思是此时Buffer中包含有之前读入Buffer中的所有字节。

第一次写操作
在我们第一次的写操作中,我们从Buffer中取出4个字节,然后写入output channel中。这个操作使得position从0增加到4,而limit没有变化,如下所示:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

第二次写操作
目前为止,只剩一个字节可写了。当我们调用flip()时,limit被设置成5,并且position不能超越limit。因此最后的写操作从Buffer取出一个字节并写入output Channel中。这次写操作会将position增加到5,而limit不变。如下所示:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

Clear操作
在我们的最后一步是调用Clear方法。这个方法会重置Buffer以准备接收新数据。Clear做了2件重要的事情:
1. 设置limit为0以匹配capacity。
2. 设置position为0。
下面的图展示了当调用完flip()之后的Buffer的状态:

Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO

一个能工作的Buffer
下面的代码总结了使用Buffer从一个Channel拷贝数据到另一个Channel
while(trie) {
  buffer.clear();
  int r = fcin.read( buffer );

  if (r==-1) {
    break;
  }

  buffer.flip();
  fcout.write( buffer );
}

read()和write()方法极大的简化了程序,由于Buffer处理了所有的细节。clear()和flip()方法用来切换Buffer的读和写。

本文参考自http://www.cs.brown.edu/courses/cs161/papers/j-nio-ltr.pdf

  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 23.6 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 37 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 29.9 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 31.6 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 31.8 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 26.9 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 27.8 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 27.8 KB
  • Java NIO 入门(四)Buffer内部原理 
            
    
    博客分类: Java JAVANIOIO
  • 大小: 33.2 KB
相关标签: JAVA NIO IO