Java NIO简介
Java NIO(New IO Non Blocking IO)是从Java1.4版本开始引入的一个新的IO API,可以替代标准的JJava IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓存区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
Java NIO与IO的主要区别
传统的IO
NIO
Java NIO系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到IO设备(例如:文件、套接字)的连接。若需要使用NIO系统,需要获取用于连接。若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。
缓冲区(Buffer)和通道(Channel)
缓冲区(Buffer)
一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
二、缓冲区存取数据的两个核心方法
- put() : 存入数据到缓冲区中
- get() : 获取缓冲区中的数据
三、缓冲区中的四个核心属性
- capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
- limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
- position: 位置,表示缓冲区中正在操作数据的位置
position <= limit <= capacity
原码:
1.分配一个指定大小的缓冲区
package com.nio.test;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
}
}
2.利用put()存入数据到缓冲区中
package com.nio.test;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//2.利用put()存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("---------------put()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
}
}
3.切换读取数据模式,利用flip()
package com.nio.test;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//2.利用put()存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("---------------put()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//3.切换读取数据模式,利用flip()
buf.flip();
System.out.println("---------------flip()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
}
}
4.利用get() 读取缓冲区中的数据
package com.nio.test;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//2.利用put()存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("---------------put()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//3.切换读取数据模式,利用flip()
buf.flip();
System.out.println("---------------flip()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//4.利用get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println("---------------get()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
System.out.println(new String(dst,0,dst.length));
}
}
5.rewind(): 将位置回到读模式,可重复读数据
package com.nio.test;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//2.利用put()存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("---------------put()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//3.切换读取数据模式,利用flip()
buf.flip();
System.out.println("---------------flip()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//4.利用get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println("---------------get()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
System.out.println(new String(dst,0,dst.length));
//5.rewind(): 将位置回到读模式,可重复读数据
buf.rewind();
System.out.println("---------------rewind()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
}
}
6.clear() : 清空缓冲区
但是缓冲区中的数据并没有清空,依然存在,但是出于"被遗忘"状态。
package com.nio.test;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import org.junit.Test;
/**
* 一、缓冲区(Buffer):在JAVA的nio中 负责数据的存取。缓存区就是数组。用于存储不同数据类型的数据。
*
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区
*
* 二、缓冲区存取数据的两个核心方法
* put() : 存入数据到缓冲区中
* get() : 获取缓冲区中的数据
*
* 三、缓冲区中的四个核心属性
* capacity: 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
* limit: 界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position: 位置,表示缓冲区中正在操作数据的位置
* position <= limit <= capacity
*
*/
public class TestBuffer {
//创建一个缓冲区
@Test
public void test1() {
String str = "abcde";
//1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("---------------allocate()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//2.利用put()存入数据到缓冲区中
buf.put(str.getBytes());
System.out.println("---------------put()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//3.切换读取数据模式,利用flip()
buf.flip();
System.out.println("---------------flip()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//4.利用get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println("---------------get()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
System.out.println(new String(dst,0,dst.length));
//5.rewind(): 将位置回到读模式,可重复读数据
buf.rewind();
System.out.println("---------------rewind()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
//6.clear() : 清空缓冲区
buf.clear();
System.out.println("---------------clear()-----------------");
System.out.println("position:"+buf.position());
System.out.println("limit:"+buf.limit());
System.out.println("capacity:"+buf.capacity());
}
}
mark:标记,表示记录当前position的位置。可以通过reset() 恢复到mark的位置
0 <= mark <= position <= limit <= capacity
@Test
public void test2() {
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst,0,2);
System.out.println(new String(dst,0,2));
System.out.println(buf.position());
//mark()标记一下
buf.mark();
//buf.get(dst, offset, length)
buf.get(dst, 2, 2);
System.out.println(new String(dst,2,2));
System.out.println(buf.position());
//reset(): 恢复到mark的标记位置
buf.reset();
System.out.println(buf.position());
}
7.hasRemaining()判断缓冲区中是否还有剩余数据
@Test
public void test2() {
String str = "abcde";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(str.getBytes());
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst,0,2);
System.out.println(new String(dst,0,2));
System.out.println(buf.position());
//mark()标记一下
buf.mark();
//buf.get(dst, offset, length)
buf.get(dst, 2, 2);
System.out.println(new String(dst,2,2));
System.out.println(buf.position());
//reset(): 恢复到mark的标记位置
buf.reset();
System.out.println(buf.position());
System.out.println("--------------------");
//判断缓冲区中是否还有剩余数据
if(buf.hasRemaining()) {
//获取缓冲区可以操作的数量
System.out.println(buf.remaining());
}
}
直接缓冲区与非直接缓冲区
- 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM内存中。
- 直接缓冲区:通过allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率。