java之NIO缓冲区Buffer的使用

 先说说传统io和Nio的区别

看如下两个图,传统的io传输是直接面对的流,面对的数据进行传输的,并且每个流都是单向的,得建立输入流输出流,但是NIO它建立的通道是双向的,程序直接面对的不是这个通道,而是缓冲区,这个缓冲区就相当于火车,通道是铁路,程序面对的是火车,往火车中存取数据,并且之建立一个通道就可以了,这就是它们之间的一个区别.

先了解一下缓冲区

 * 缓存区(Buffer) 在Java NIO 中负责数据的存储.缓冲区就是数组.用于存储不同数据类型的数据
 * 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区
 * ByteBuffer
 * charBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * DoubleBuffer
 * FloutBuffer

所有的缓冲区都是继承了Buffer这个类

在Buffer里面又有四个属性,这四个属性非常重要

 * capacity:容量,表示缓冲区中最大存储数据的容量,一旦声明不能改变.
 * limit:界限,表示缓冲区中可以操作数据的大小.(limit后数据不能机进行读写)
 * position:位置,表示缓冲区中正在操作数据的位置.

如下图,新创建的Buffer,就是第一行的效果,当往里面写数据的时候是第二行的效果,当调用的flip()方法的时候,就变成读数据模式,也就是第三行效果

这个是写入了五个数据

读数据模式

取出来这几个数据时,position的位置就和limit的位置相同了

rewind()这个方法就是重复读数据,position就又回到起点了

clear这个方法情空的只是那三个属性的值,里面的数据不会丢失,只不过不知道里面又多少数据了.

这时就用到第四个属性了,mark,它是记录当前position的位置的,配合reset使用,但是在使用reset的时候,不能使用clear不然会报错,mark它只是记录position位置的,如果clear后就记录不了了.

hasRemaining()是判断是否还有可操作数量remaining()是获取可操作数量

 直接缓冲区与非直接缓冲区
 非直接缓冲区:通过allocate() 方法分配缓冲区,讲缓冲区建立在JVM的内存中
 直接缓冲区:通过allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中.可以提高效率

以上操作包括传统的io都是以非直接缓冲区的形式传输数据的,NIO正是用的直接缓冲区才能提高效率,但是直接缓冲区是直接建立在物理内存中的,非常消耗资源,所以使用的时候也要适当考虑时机,直接缓存区在应用程序种写入物理内存后就跟程序没关系了,控制不了什么时候写完,直到垃圾回收器收回后才于物理内存的连接断开,不然会一直占用物理内存的资源.

非直接缓冲区在堆内存中,也就是使用的数组.

直接缓冲区是调用的操作系统的内存方法

判断是否是直接缓冲区

package com.bgs.nio;

import java.nio.ByteBuffer;

import org.junit.Test;

/*
 * 缓存区(Buffer) 在Java NIO 中负责数据的存储.缓冲区就是数组.用于存储不同数据类型的数据
 * 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区
 * ByteBuffer
 * charBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * DoubleBuffer
 * FloutBuffer
 * 上述缓冲区的管理方式几乎一致,通过allocate() 获取缓冲区
 * 二.缓冲区存取数据的两个核心方法:
 * put() 存入数据到缓冲区
 * get() 获取缓冲区的数据
 * 
 * 四:缓冲区中的四个核心属性:
 * capacity:容量,表示缓冲区中最大存储数据的容量,一旦声明不能改变.
 * limit:界限,表示缓冲区中可以操作数据的大小.(limit后数据不能机进行读写)
 * position:位置,表示缓冲区中正在操作数据的位置.
 * 
 * mark:标记,表示记录当前position的位置,可以通过reset() 恢复到mark的位置
 * 
 * 0 <= mark <= position <= limit <= capacity
 * 
 * 五.直接缓冲区与非直接缓冲区
 * 非直接缓冲区:通过allocate() 方法分配缓冲区,讲缓冲区建立在JVM的内存中
 * 直接缓冲区:通过allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中.可以提高效率
 * 
 */
public class TestBuffer {
	@Test
	public void test1(){
		
		String str = "abcde";
		
		//1.分配一个指定大小的缓冲区
		ByteBuffer buf = ByteBuffer.allocate(1024);
		
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
		
		//2.利用put()存入数据到缓冲区中
		buf.put(str.getBytes());
		System.out.println("put()----------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
		
		//3.切换成读取数据的模式
		buf.flip();
		System.out.println("flip()----------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
		
		//4.利用get() 读取缓冲区中的数据
		byte[] d = new byte[buf.limit()];
		buf.get(d);
		System.out.println("get()----------");
		System.out.println(new String(d));
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
		
		//5.rewind 可重复读数据
		buf.rewind();
		System.out.println("rewind()----------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
		
		//6.clear() 清空缓冲区   只是指针回归原位了
		//但是里面数据还在
		buf.clear();
		
		byte[] f = new byte[buf.limit()];
		buf.get(f);
		System.out.println("get()----------");
		System.out.println(new String(f));
		
		
		System.out.println("clear()----------");
		System.out.println(buf.position());
		System.out.println(buf.limit());
		System.out.println(buf.capacity());
	}
	
	@Test
	public void test2(){
		String str = "abcde";
		ByteBuffer buf = ByteBuffer.allocate(1024);
		buf.put(str.getBytes());
		buf.flip();
		byte[] d = new byte[buf.limit()];
		buf.get(d,0,2);
		System.out.println(new String(d,0,2));
		System.out.println(buf.position());
		buf.mark();
		buf.get(d,2,2);
		System.out.println(new String(d,2,2));
		System.out.println(buf.position());
		//reset() 恢复到mark1的位置
		buf.reset();
		System.out.println(buf.position());
		buf.clear();
		System.out.println("--------");
		buf.reset();
		System.out.println(buf.position());
		//判断是否还有数据
		if(buf.hasRemaining()){
			//获取可以操作的数据数量
			System.out.println(buf.remaining());
		}
		
	}
	
	@Test
	public void test3(){
		//分配直接缓冲区
		ByteBuffer buf = ByteBuffer.allocateDirect(1024);
		
		System.out.println(buf.isDirect());
		
		
		
		
	}
	
}

下一篇是java之NIO通道Channel的使用https://blog.csdn.net/kxj19980524/article/details/86560157

猜你喜欢

转载自blog.csdn.net/kxj19980524/article/details/86559495
今日推荐