Java NIO技术学习之二

来源:互联网 发布:unity3d游戏大全 编辑:程序博客网 时间:2024/06/07 07:03

在上一篇中,我们介绍了NIO中的两个核心对象:缓冲区和通道。本文为NIO入门学习的第二篇,将会分析NIO中的缓冲区Buffer的内部原理。

在谈到缓冲区时,我们说缓冲区对象本质上是一个数组,但它其实是一个特殊的数组,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况,如果我们使用get()方法从缓冲区获取数据或者使用put()方法把数据写入缓冲区,都会引起缓冲区状态的变化。

在缓冲区中,最重要的属性有下面三个,它们一起合作完成对缓冲区内部状态的变化跟踪:

position

指定了下一个将要被写入或者读取的元素索引。在从Channel读取数据到Buffer时,position变量用来跟踪截止目前为止从Channel中读出了多少数据,在从Buffer中向Channel写数据时,position变量用来跟踪截止目前为止向Channel写入了多少数据。

limit

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

capacity

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


接下来我们将逐一检查每个细节,并且也看看为什么这样的设计适合典型的读/写(输入/输出)处理。我们假设从一个Channel拷贝数据到另一个Channel。

首先新建一个容量大小为10的ByteBuffer对象,在初始化的时候,position设置为0,如果我们读一些数据到缓冲区中,那么下一个读取的数据就进入索引为0的字节。如果我们从缓冲区写一些数据,从缓冲区读取的下一个字节就来自索引为0的字节。limit和 capacity被设置为10,在以后使用ByteBuffer对象过程中,capacity的值不会再发生变化,而其它两个将会随着使用而变化。


现在我们可以从读通道中读取一些数据到缓冲区中。如果读取到4个字节数据,则此时position的值为4,即下一个将要被写入的字节索引为4,而limit仍然是10,如下图所示:


下一步把读取到的数据写入到写通道中,在此之前必须调用flip()方法,该方法将会完成两件事情:

1. 把limit设置为当前的position值

2. 把position设置为0

position 被设置为 0,这意味着我们得到的下一个字节是第一个字节。limit 已被设置为原来的 position,这意味着它包括以前读到的所有字节,并且一个字节也不多,如下图所示:


我们现在可以将数据从缓冲区写入通道了,这会导致position的增加而limit保持不变,但position不会超过limit的值,所以在读取我们之前写入到缓冲区中的4个字节之后,position和limit的值都为4,如下图所示:


在数据写入到写通道完毕后,调用clear()方法能够把所有的状态变化设置为初始化时的值,该方法将会完成两件事情:

1. 把limit设置为capacity值

2. 把position设置为0

clear()方法会重置Buffer以便接收更多的字节,如下图所示:


最后我们用一段代码来验证这个过程,如下所示:

import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.Buffer;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class TestBufferField {    public static void main(String[] args) throws Exception {        FileInputStream fileInStream = new FileInputStream("D:\\test1.txt");        // 获取读通道        FileChannel fcin = fileInStream.getChannel();        FileOutputStream fileOutStream = new FileOutputStream("D:\\test2.txt");        // 获取写通道        FileChannel fcout = fileOutStream.getChannel();        // 创建缓冲区        ByteBuffer buffer = ByteBuffer.allocate(10);        output("初始化", buffer);        // 从通道fcin读取数据到缓冲区        fcin.read(buffer);        output("调用read()", buffer);        // 重设buffer,将limit设置为position,然后将position设置为0        buffer.flip();        output("调用flip()", buffer);        // 将缓冲区中的数据写入通道fcout        fcout.write(buffer);        output("调用write()", buffer);        // 重设buffer,将limit设置为容量capacity,position设置为0        buffer.clear();        output("调用clear()", buffer);        fileInStream.close();        fileOutStream.close();    }    public static void output(String step, Buffer buffer) {        System.out.println(step + " : ");        System.out.print("position: " + buffer.position() + ", ");        System.out.print("limit: " + buffer.limit() + ", ");        System.out.println("capacity: " + buffer.capacity());        System.out.println();    }}

输出结果为:


这与我们上面演示的过程一致。在后面的文章中,我们继续介绍NIO中关于缓冲区一些更高级的使用。


参考:

Java NIO使用及原理分析(二)

NIO 入门



原创粉丝点击