先说说传统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());
}
}