NIO01

NIO

一.NIO的基本定义

java.nio全称java non-blocking IO,是指jdk1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。(百度百科)

  • 对原始数据类型提供一套缓存容器。
  • 作用是使用缓存容器(Buffer类)来进行数据的读写操作。

二.NIO和IO的区别

IONIO
面向流(Stream Oriented)面向缓冲区(Buffer Oriented)
单向数据操作(in只能读,out只能写)双向数据操作,所有数据存放到buffer缓冲区中既可以读也可以写入.(缓冲区要放到通道中)
阻塞IO(Blocking IO)非阻塞IO(Non Blocking IO)
(无)选择器(Selectors)

三.基于普通的通道和缓冲区的NIO操作

Java NIO系统的核心在于:通道(Channel)和缓冲区 (Buffer)。通道表示打开到 IO 设备(例如:文件、 套接字)的连接。若需要使用 NIO 系统,需要获取 用于连接 IO 设备的通道以及用于容纳数据的缓冲 区。然后操作缓冲区,对数据进行处理。

  • 通道是连接程序与目标文件的管道。
  • 缓冲区是用来存放要传输的数据的。
  • 缓冲区是依靠通道进行传输的。
    Channel负责传输,Buffer负责存储。
    在这里插入图片描述

1.缓冲区

1.1 NIO的缓冲区是java中提供的除了boolean类型以外的基本数据类型的缓存容器,都是来自于Buffer。

在这里插入图片描述

1.2Java提供了7个用来存放数据的容器:

ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer

1.3缓冲区有三个重要的属性:capacity,position,limit.
  • position(起始值)和limit(有效数据值)的含义取决于Buffer处在读模式还是写模式。
  • capacity缓冲区的容量大小,在创建缓冲区的时候需要手动指定 .

详细解释:

  • capacity:作为一个内存块,Buffer有固定的大小值,也叫作“capacity”,只能往其中写入capacity个byte、long、char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清楚数据)才能继续写数据。
  • position:当你写数据到Buffer中时,position表示当前的位置。初始的position值为0,当写入一个字节数据到Buffer中后,position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity-1。当读取数据时,也是从某个特定位置读,讲Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取一个字节数据后,position向前移动到下一个可读的位置。
  • limit:在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position)
  • 标记 (mark)与重置 (reset):标记是一个索引,通过 Buffer 中的 mark() 方法指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这 个 position.
1.4具体的使用操作

步骤: 写入----读取操作

  • 创建缓冲区,指定缓冲区容量 。
  • 写入数据。
  • 切换模式(从写到读或者从读–写)
  • 展示数据。
1.5Buffer类常用方法

在这里插入图片描述
ByteBuffer类方法

(1)static ByteBuffer
allocate(int capacity) 分配一个新的字节缓冲区。

1.6缓冲区的数据操作
  • Buffer 所有子类提供了两个用于数据操作的方法:get() 与 put() 方法

获取 Buffer 中的数据

  • get() :读取单个字节
  • get(byte[] dst):批量读取多个字节到 dst 中
  • get(int index):读取指定索引位置的字节(不会移动 position)

放入数据到 Buffer 中

  • put(byte b):将给定单个字节写入缓冲区的当前位置
  • put(byte[] src):将 src 中的字节写入缓冲区的当前位置
  • put(int index, byte b):将指定字节写入缓冲区的索引位置(不会移动 position)
  • put(byte[] src, int offset, int length) 相对批量 put 方法(可选操作)。
    (src - 要从中读取字节的数组
    offset - 要读取的第一个字节在数组中的偏移量;必须为非负且不大于 array.length
    length - 要从给定数组读取的字节的数量;必须为非负且不大于 array.length - offset )
	@Test
	void bufferDemo() {
		//创建缓冲区
		ByteBuffer buffer = ByteBuffer.allocate(10);//容量为10
		//三个属性      写入模式
		System.out.println(" ================== 写入模式 ========================");
		System.out.println("总容量:"+buffer.capacity());//总容量:10
		System.out.println("写入的起始标记:"+buffer.position());//写入的起始标记:0
		System.out.println("写入时的limit: "+buffer.limit());//写入时的limit: 10
		
		//转为读取模式
		buffer.flip();
		System.out.println(" ================== 读模式 ========================");
		System.out.println("总容量:"+buffer.capacity());//总容量:10
		System.out.println("读取的起始标记:"+buffer.position());//读取的起始标记:0
		System.out.println("读取时的limit: "+buffer.limit());//读取时的limit: 0
		
		
		
		//给缓冲区写入数据
		String mess="abcde";
		ByteBuffer put = buffer.put(mess.getBytes());
		System.out.println(" ================== 写入数据之后 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("写入的起始标记:"+buffer.position());
		System.out.println("写入时的limit:"+buffer.limit());
		
		//转为读取模式
		//position会随从缓冲区中读取数据的个数而改变,limit也会改变
		buffer.flip();
		System.out.println(" ================== 读模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
		
		
		//使用get方法读取数据
		byte[] dest=new byte[buffer.limit()];
//		byte b = buffer.get();//读取一个
//		System.out.println((char)b);
		buffer.get(dest);//读取所有
		System.out.println(new String(dest));
		
		buffer.flip();  
		buffer.limit(buffer.capacity());//设置limit位置
		buffer.clear();
		System.out.println(" ==================读取数据之后转为写入模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
		
	}
	
@Test
	void buffer01() {
		ByteBuffer buffer = ByteBuffer.allocate(10);
		//三个属性      写入模式
		System.out.println(" ================== 写入模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("写入的起始标记:"+buffer.position());
		System.out.println("写入时的limit: "+buffer.limit());
		
		//写入数据
		buffer.put("abcdef".getBytes());
		
		//转为读模式
		buffer.flip();
		System.out.println(" ================== 读模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
		
		//此时并没有读取缓冲区中的数据
		//获取缓冲区中的数据(读取中的内容是position--limit(不包含)之间的数据)
		byte [] bt=new byte[buffer.limit()];
		buffer.get(bt);
		System.out.println(new String(bt));
		
//		buffer.get();
//		byte b = buffer.get();
//		System.out.println(b);
		
		//重新读取,将position.limit重新设置
		buffer.rewind();
		//自定义设置标记
		buffer.position(0);
		buffer.limit(4);
		
		System.out.println(" ================== 读模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
		
		buffer.flip();
		buffer.clear();//清空数据,就是将所有的标记进行恢复,恢复到初始化
		System.out.println(" ================== 写入模式 ========================");
		System.out.println("总容量:"+buffer.capacity());
		System.out.println("写入的起始标记:"+buffer.position());
		System.out.println("写入时的limit: "+buffer.limit());
		
		//清空缓冲区,只是将数据隐藏,并没有彻底清空
		System.out.println((char)buffer.get());
		
	}
  • mark标记和reset重置
//mark标记和reset重置
	@Test
	void buffer02() {
		//创建缓冲区
		ByteBuffer buffer = ByteBuffer.allocate(10);
		buffer.put("abcdef".getBytes());//实际要写入的字节个数要小于等于capacity
		//读取操作,读取123
		buffer.flip();
		byte[] bt=new byte[3];
		buffer.get(bt);//==buffer.get(bt,0,bt.length);
		//给第一次读取做一个标记position 3 limit 6
		buffer.mark();
		//读取456
		buffer.get(bt);
		System.out.println(new String(bt));
		System.out.println(" ================== 读模式 ========================");
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
		
		//恢复到第一次读取之后的标记
		buffer.reset();
		System.out.println(" ================== reset ========================");
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit:"+buffer.limit());
	}
	
  • 容器的容量是10,存的数据是20
//容器的容量是10,存的数据是20
	@Test
	void buffer03() {
		ByteBuffer buffer = ByteBuffer.allocate(10);
		String mess="12345678901234567890";
		//存进去
		byte[] bytes=mess.getBytes();
		buffer.put(bytes,0,buffer.capacity());
		System.out.println("================= write =====================");
		System.out.println("读取的起始标记:"+buffer.position());
		System.out.println("读取时的limit"+buffer.limit());
		//读出来
		buffer.flip();
		byte[] b=new byte[buffer.limit()];
		buffer.get(b);
		System.out.println(new String(b));
		
	}
	
  • 循环,先先进去,在读出来
@Test
	void buffer04() {
		Scanner input=new Scanner(System.in);
		//容量为10
		ByteBuffer buffer = ByteBuffer.allocate(10);
		String mess=" 1234568822读书是一件aaadd快乐的事情。对于爱读书的人一但读上5823就让人欲罢不能,无法放弃读书,想让人swwdddd读到天涯海角。有人说:“人生最深最平和的快乐,就是静观天地与人生,慢慢fdddsssss品味出它的和谐与美。”静下心来,翻开书本,那些沉adfgvffff积的墨香一点点溢满空间,那些尘封的快fffffff乐一点点打开。读书真的很快乐!";
		byte[] bytes=mess.getBytes();
		//循环
		boolean flag=true;
		int index=0;
		while(flag) {
			//写
			int len=0;
			if(buffer.capacity()>(mess.length()-index)) {
				len=mess.length()-index;
			}else {
				len=buffer.capacity();
			}
			buffer.put(bytes,index,len);
			//转为读模式
			buffer.flip();
			//读取
			byte[] b=new byte[buffer.limit()];
			buffer.get(b);
			System.out.println("读到的数据是"+new String(b));
			index+=buffer.position();//对缓冲的操作
			System.out.println("下一次写入时字符串的起始下标"+index);
			//转为写模式
			String next=input.next();
			buffer.flip();
			if(index==mess.length()) {
				flag=false;
			}
		}
	}
1.6.1非直接缓冲区

在这里插入图片描述

非直接缓冲区写入步骤:

  • 创建一个临时的直接ByteBuffer对象。
  • 将非直接缓冲区的内容复制到临时缓冲中。
  • 使用临时缓冲区执行低层次I/O操作。
  • 临时缓冲区对象离开作用域,并最终成为被回收的无用数据。
1.6.2直接缓冲区

在这里插入图片描述

1.6.3判断是否是直接缓冲区还是非直接缓冲区

abstract boolean
isDirect() 判断此字节缓冲区是否为直接的(子类的方法)。

  • 非直接缓冲区:java—JVM(缓冲区)—物理内存区
  • 直接缓冲区:javaAPP—JVM(省略)----物理内存区
  • 读取数据的读取速度
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值