Java 之NIO(一) - 简介(Buffer)

简介

晒酷学院qq群:979438600
NIO是New IO 的简称,在jdk1.4 里提供的新api。
与原始的java io包中面向流(stream-oriented)概念不同,NIO中采用面向块的(block-oriented)概念,这意味着在尽可能的情况下,IO操作以块为单位进行,而不是字节/字符为单位,采用这种方式可以使Java IO性能有大幅提高。
另外,与面向线程的,阻塞式IO方式相比,多道通信,非阻塞式IO机制可以更加有效的处理大量连接的应用程序。
新IO除了原有功能之外,还提供了以下新特性:
1.多路选择的,非阻塞式IO机制
2.支持文件锁及内存映射
3.支持正则表达式的模式匹配设施
4.字符集编码器和译码器
在新IO中通过使用Buffer和Channel支持以上特性。
Buffer(缓冲区)
在NIO中所有操作都需要使用缓冲区处理,所有的读写都是通过缓冲区来完成的,缓冲区是一个线性的,有序的数据集,只能存储基本数据类型。
关于Buffer类的常用方法,请查阅javadoc文档,这里不再一一列出,NIO中针对每一种基本数据类型都有一个相应的缓冲区操作类,包括(ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer),关于各缓冲区操作类的方法,请查阅javadoc文档。

1. Buffer的基本用法

代码如下:

package com.ray.nio.demo;
import java.nio.IntBuffer;

/**
 * 缓冲区的基本操作
 * 
 * 在Buffer中存在一系列状态变量,用于记录操作缓冲区内容的指针位置(position),指针的操作边界(limit),缓冲区大小(capacity)
 * position:表示下一个操作(读/写)的指针,指针永远放在最后(读/写)入的数据位置之后
 * limit:limit为定界position指针的操作边界,position<limit
 * capacity:定义缓冲区大小
 * 本示例程序操作步骤:
 * 1.为IntBuffer开辟缓冲区
 * 2.向缓冲区写入数据
 * 3.调用flip方法,重设缓冲区 操作指针(position)、操作边界(limit)的位置
 * 4.遍历缓冲区数据
 * 
 * @author xuleilei
 *
 */
public class IntBuffer01 {
	public static void main(String[] args) {
		IntBuffer intBuffer = IntBuffer.allocate(10);
		
		System.out.println("未写入数据时的缓冲区:position:" + intBuffer.position() + ",limit:" + intBuffer.limit() + ",capacity:" + intBuffer.capacity());
		
		int pre = 0,arrs[] = {1,3,5};
		intBuffer.put(pre);
		intBuffer.put(arrs);
//		intBuffer.put(6, 9);	此处写入数据无效,确保缓冲区起始数据依次连续存储数据
		
		System.out.println("写入数据后的缓冲区:position:" + intBuffer.position() + ",limit:" + intBuffer.limit() + ",capacity:" + intBuffer.capacity());
		
//		重设缓冲区,将
		intBuffer.flip();
		System.out.println("调用filp方法后的缓冲区:position:" + intBuffer.position() + ",limit:" + intBuffer.limit() + ",capacity:" + intBuffer.capacity());
		
//		读取缓冲区中的内容
//		System.out.print(intBuffer.get(3));
		while(intBuffer.hasRemaining()){
			System.out.print(intBuffer.get() + "、");
		}
	}
}

2.创建子缓冲区

package com.ray.nio.demo;
import java.nio.IntBuffer;

/**
 * 创建子缓冲区
 * 
 * NIO中可以使用各缓冲区类的slice方法从一个缓冲区中创建一个子缓冲区,子缓冲区与原缓冲区共享数据
 * 
 * @author xuleilei
 *
 */
public class IntBuffer02 {
	public static void main(String[] args) {
//		开辟缓冲区空间,声明子缓冲区
		IntBuffer intBuffer = IntBuffer.allocate(10),subBuffer = null;
		
//		向缓冲区中填充数据,10个偶数
		for(int i = 0;i < 10;i++){
			intBuffer.put(i*2);
		}
//		将缓冲区的position指针设置在第三个元素上,并设置边界为5
		intBuffer.position(2);
		intBuffer.limit(5);
//		开辟子缓冲区
		subBuffer = intBuffer.slice();

//		修改子缓冲区数据
		for(int i=0;i<subBuffer.capacity();i++){
			subBuffer.put(subBuffer.get(i) - 1);
		}
//		重设缓冲区
		intBuffer.flip();
		intBuffer.limit(intBuffer.capacity());
//		读取缓冲区中的内容
		while(intBuffer.hasRemaining()){
			System.out.print(intBuffer.get() + "、");
		}
	}
}

3.创建只读缓冲区

package com.ray.nio.demo;
import java.nio.IntBuffer;

/**
 * 创建只读缓冲区
 * 
 * 如果希望使用缓冲区的内容,但又不希望缓冲区内容被修改,则可以通过asReadOnlyBuffer创建一个只读缓冲区。
 * 注意:创建后的只读缓冲区不能变为可写状态
 * @author xuleilei
 *
 */
public class IntBuffer03 {
	
	public static void main(String[] args) {
		IntBuffer intBuffer = IntBuffer.allocate(10);
		IntBuffer intBufferReadOnly = null;
		
		int pre = 0,arrs[] = {1,3,5};
		intBuffer.put(pre);
		intBuffer.put(arrs);
//		将缓冲区变为只读缓冲区,注意在转换为只读缓冲区之前,原缓冲区确保
		intBufferReadOnly = intBuffer.asReadOnlyBuffer();
//		重设缓冲区
		intBufferReadOnly.flip();
//		读取缓冲区中的内容
		while(intBufferReadOnly.hasRemaining()){
			System.out.print(intBufferReadOnly.get() + "、");
		}
//		向只读缓冲区中写入数据,非法!!!
		intBufferReadOnly.put(222);
	}


}

4.创建直接缓冲区

在介绍如何创建直接缓冲区前,先简单介绍下直接缓冲区和非直接缓冲区:
操作系统有用户空间与系统空间的概念,JVM对应的JAVA进程是位于用户空间的,处于该空间的进程不能直接访问硬件设备,当JAVA进程要进行I/O操作时,只能通过系统调用将控制权交给内核,内核准备好进程所需要的数据,将这些数据拷贝到用户空间缓冲区(如下图所示)

字节缓冲区要么是直接的,要么是非直接的,最大的区别是于内存位置不同。直接缓冲区可以通过allocateDirect方法来创建,也可以通过内存映射来创建,如果为直接字节缓冲区JVM会尽最大努力直接在此缓冲区上执行本机 I/O 操作。
非直接缓冲区写入步骤:
1.创建一个临时的直接ByteBuffer对象。
2.将非直接缓冲区的内容复制到临时缓冲中。
3.使用临时缓冲区执行低层次I/O操作。
4.临时缓冲区对象离开作用域,并最终成为被回收的无用数据。
如果采用直接缓冲区会少一次复制过程,如果需要循环使用缓冲区,用直接缓冲区可以很大地提高性能。虽然直接缓冲区使JVM可以进行高效的I/o操作,但它使用的内存是操作系统分配的,绕过了JVM堆栈,建立和销毁比堆栈上的缓冲区要更大的开销

package com.ray.nio.demo;
import java.nio.ByteBuffer;
/**
 * 创建直接缓冲区
 * @author xuleilei
 *
 */
public class IntBuffer04 {
	public static void main(String[] args) {
		ByteBuffer byteBuf = ByteBuffer.allocateDirect(10);
		
		byte arrs[] = {1,3,5};
		byteBuf.put(arrs);
//		重设缓冲区
		byteBuf.flip();
//		读取缓冲区中的内容
		while(byteBuf.hasRemaining()){
			System.out.print(byteBuf.get() + "、");
		}
	}
}
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页