Java NIO入门学习(二)

在上一篇中,我们介绍了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 入门



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值