Java NIO学习3(缓冲区1)

1 什么是缓冲区?
Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中, 您将数据直接写入或者将数据直接读到 Stream 对象中。
在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。 任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。

缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。

缓冲区类型
最常用的缓冲区类型是 ByteBuffer。一个 ByteBuffer 可以在其底层字节数组上进行 get/set 操作(即字节的获取和设置)。
ByteBuffer 不是 NIO 中唯一的缓冲区类型。事实上,对于每一种基本 Java 类型都有一种缓冲区类型:
. ByteBuffer
. CharBuffer
. ShortBuffer
. IntBuffer
. LongBuffer
. FloatBuffer
. DoubleBuffer

每一个 Buffer 类都是 Buffer 接口的一个实例。 除了 ByteBuffer,每一个 Buffer 类都有完全一样的操作,只
是它们所处理的数据类型不一样。因为大多数标准 I/O 操作都使用 ByteBuffer,所以它具有所有共享的缓冲区操作
以及一些特有的操作。
现在您可以花一点时间运行 UseFloatBuffer.java,它包含了类型化的缓冲区的一个应用例子。

FloatBuffer buffer = FloatBuffer.allocate(10);
		
		for (int i = 0; i < buffer.capacity(); i++) {
			float f = (float)Math.sin( (((float)i)/10)*(2*Math.PI) );  
			buffer.put(f);
		}
		
		buffer.flip();
		
		while (buffer.hasRemaining()) {
			System.out.println(buffer.get());
		}

缓冲区内部细节

NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor)。

在从通道读取数据时,数据被放入到缓冲区。在有些情况下,可以将这个缓冲区直接写入另一个通道,但是在一般情况下,您还需要查看数据。这是使用 访问方法get() 来完成的。同样,如果要将原始数据放入缓冲区中,就要使用访问
方法 put()。



状态变量
可以用三个值指定缓冲区在任意时刻的状态:
. position
. limit
. capacity
这三个变量一起可以跟踪缓冲区的状态和它所包含的数据。


详细介绍这三个变量

一个 buffer 主要由 position,limit,capacity 三个变量来控制读写的过程。此三个变量的含义见如下表格:

参数

写模式   

读模式

position

当前写入的单位数据数量。

当前读取的单位数据位置。

limit

代表最多能写多少单位数据和容量是一样的。

代表最多能读多少单位数据,和之前写入的单位数据量一致。

capacity

buffer 容量

buffer 容量




访问方法:
到目前为止,我们只是使用缓冲区将数据从一个通道转移到另一个通道。然而,程序经常需要直接处理数据。例如,您可能需要将用户数据保存到磁盘。在这种情况下,您必须将这些数据直接放入缓冲区,然后用通道将缓冲区写入磁盘。
或者,您可能想要从磁盘读取用户数据。在这种情况下,您要将数据从通道读到缓冲区中,然后检查缓冲区中的数据。

get() 方法
ByteBuffer 类中有四个 get() 方法:
1. byte get();
2. ByteBuffer get( byte dst[] );
3. ByteBuffer get( byte dst[], int offset, int length );
4. byte get( int index );
第一个方法获取单个字节。第二和第三个方法将一组字节读到一个数组中。第四个方法从缓冲区中的特定位置获取字节。
那些返回 ByteBuffer 的方法只是返回调用它们的缓冲区的 this 值。
此外,我们认为前三个 get() 方法是相对的,而最后一个方法是绝对的。 相对意味着 get() 操作服从 limit 和position 值 ― 更明确地说,字节是从当前 position 读取的,而 position 在 get 之后会增加。
另一方面,一个 绝对方法会忽略 limit 和 position 值,也不会影响它们。事实上,它完全绕过了缓冲区的统计方法。
上面列出的方法对应于 ByteBuffer 类。其他类有等价的 get() 方法,这些方法除了不是处理字节外,其它方面是是完全一样的,它们处理的是与该缓冲区类相适应的类型。

put()方法
ByteBuffer 类中有五个 put() 方法:
1. ByteBuffer put( byte b );
2. ByteBuffer put( byte src[] );
3. ByteBuffer put( byte src[], int offset, int length );
4. ByteBuffer put( ByteBuffer src );
5. ByteBuffer put( int index, byte b );
第一个方法 写入(put) 单个字节。第二和第三个方法写入来自一个数组的一组字节。第四个方法将数据从一个给定的源 ByteBuffer 写入这个 ByteBuffer。第五个方法将字节写入缓冲区中特定的 位置 。那些返回 ByteBuffer 的方法只是返回调用它们的缓冲区的 this 值。
与 get() 方法一样,我们将把 put() 方法划分为 相对或者 绝对的。前四个方法是相对的,而第五个方法是绝对的。
上面显示的方法对应于 ByteBuffer 类。其他类有等价的 put() 方法,这些方法除了不是处理字节之外,其它方面是完全一样的。它们处理的是与该缓冲区类相适应的类型。

类型化的 get() 和 put() 方法
除了前些小节中描述的 get() 和 put() 方法, ByteBuffer 还有用于读写不同类型的值的其他方法,如下所示:
. getByte()
. getChar()
. getShort()
. getInt()
. getLong()
. getFloat()
. getDouble()
. putByte()
. putChar()
. putShort()
. putInt()
. putLong()
. putFloat()
. putDouble()
事实上,这其中的每个方法都有两种类型 ― 一种是相对的,另一种是绝对的。它们对于读取格式化的二进制数据( 如图像文件的头部)很有用。
您可以在例子程序 TypesInByteBuffer.java 中看到这些方法的实际应用。

缓冲区的使用:一个内部循环
下面的内部循环概括了使用缓冲区将数据从输入通道拷贝到输出通道的过程。
while (true) {
buffer.clear();
int r = fcin.read( buffer );
if (r==-1) {
break;
}
buffer.flip();
fcout.write( buffer );
}
read() 和 write() 调用得到了极大的简化,因为许多工作细节都由缓冲区完成了。 clear() 和 flip() 方法用于让缓冲区在读和写之间切换。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值