状态变量是上一节中提到的“内部计数系统”的关键,随着每次读写操作,状态变量都在发生变化。通过记录和追踪这些变化,buffer有能力在内部管理其自身的一些资源。
当你从channel中读取数据的时候,数据已经在buffer中了。在一些情况下,你可以将这个buffer直接的写到另一个channel中,但是通常,你希望看看这些数据。这可以通过get()方法来优雅的实现,同样的,当你想往buffer中放入数据时,你也可是使用put()方法。
在这一节中,你将学到NIO中一些关于状态变量和存取方法。在起初看来NIO的内部计数系统很复杂,但你却可以很快的看到它在内部为你做了很多事情。你可能习惯与手写账簿--使用字节数组和下标变量--已经在NIO内部被处理了。
状态变量
在任何时候,buffer中有三个变量可以明确的表示buffer的状态。
这三个变量追踪和记录buffer的状态和包含的数据,我们马上来详细的解剖这三个变量,并且看看他们是如何使用于典型的读写进程的。为了举例的方便,我们假设正在从一个input channel中复制数据到output channel中。
Position:
你可能会知道buffer实际上是一个优化了的数组,当你从channel中读入数据时,你将数据读入到底层的数组中。这个position变量保存这你写入了多少数据。更精确的说,它指定了底层数组使用的下一个下标。因此,当你从一个channel中读入了3个字节的数据后,buffer的position就将被设置为3,标识着数组的第四个元素。
同样的,当你从一个buffer中读入数据写到另一个channel中时,这个position变量保存着你从buffer中取出了多少数据。更精确的说,它指定了你从数组元素中读取的下一个下标。因此,如果你从buffer中读取了5byte的数据写入到channel中,buffer的position将被设置为5,也标识着数组中的第六个元素。
Limit
limit变量指定了还剩多少数据可以取得(在将数据从buffer中写入到channel的情况下)或者还有多少空位可以存放元素(在从一个channel中读入数据到buffer的情况下)。position总是小于或者等于limit。
Capacity
capacity指定了buffer中最多可以存放多少数据。实际上,他是底层数组的大小,或者至少是我们允许使用的底层数组的大小。
图示:
我们从一个新创建的buffer开始,为了演示的方便,我们假设buffer的capacity只有8个字节,现在buffer的状态如下:
回忆一下limit不可能比capacity大,并且在这种情况下,其值也为8.我们将其也指在数组的末尾。
此时position的值为0,如果我们从别处读入数据到buffer中,则下一个字节所存放的位置就是下标0表示的位置,如果我们从buffer中写出数据,则下一个读出的数据的下标也为0所代表的位置,position的位置如下:
由于capacity没有发生改变,所以在接下来的讨论中忽略capacity这个值。
第一次读:
现在我们准备在我们新创建的buffer上进行读/写操作。我们开始从input channel中读入一些数据到buffer中,第一次取得3个字节,他们都被放入到以position开始的数组下标中,经过这次读操作后,position值增至3,下面是图示:
当然,limit值没有发生改变。
第二次读,我们从input channel中读入2字节的数据到buffer中,这两字节数据也存放在以position开始的数组下标中,同时position又增加了2.如下图示:
此时limit的值同样没有发生变化。
The flip
现在我们准备将数据从buffer写回到output channel中,在我们进行此项操作之前,我们必须调用flip()方法,这个方法做了两件重要的事情:
上一张图片显示的是flip()之前的状态,下图显示的是调用flip()之后的状态:
现在我们已经准备好了将数据从buffer中写回到channel中了,position已经被重置为0了,表明着下一次读取的数据的下标为0,并且limit也已经设置为原来的position,意味着我们可以读入的数据的总数。
第一次写:
在我们的第一次写中,我们从buffer中取出了4个字节的数据并且将他们写回到了output channel中,这样position的值就变为了4,同样limit的值没有发生变化,如下图:
第二次写:
现在我们还有两字节的数据可以被写出,limit的值为5,position的值不能超过5,所以最后一次只能读入一个数据写回到output channel中,现在position的值为5,limit的值没有发生变化,如下图:
clear()方法:
最后一步我们调用了buffer的clear方法,这个方法重置了buffer以便让他重新接受数据,clear()做了两件主要的事情:
下图表明了调用clear()方法之后的状态:
现在buffer可以接受新数据了。
下一节我们讲述buffer中一些方法的基本使用。