Java NIO(New IO)是一个可以替代标准Java IO API的IO API,标准IO基于字节流河字符流进行操作,而NIO基于通道Channel
和缓冲区Buffer
进行操作,数据总是从Channel读取到Buffer,或者从Buffer写入Channel中。
Buffer负责数据的读写,Channel负责数据的传输。
Buffer就是数组,用于存储不同类型的数据,NIO针对不同数据类型提供了相应的缓冲区:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
缓冲区读写数据的主要方法分别为:
get()
set()
flip()
rewind()
mark()
set()
clear()
缓冲区中有4个核心属性,其中position<=limit<=capacity
capacity(容量)
:缓冲区的最大容量,一旦声明不能改变;
limit(界限)
:缓冲区中可以操作的数据范围(limit后的数据不能读写);
position(位置)
:缓冲区中正在操作的数据位置;
mark(标记)
:mark()
可以记录当前position的位置,reset()
可以恢复到mark位置。
接下来用代码来演示BtyeBuffer这种类型的的API
import java.nio.ByteBuffer;
public class TestBuffer {
public static void main(String[] args) {
// 1.分配指定大小1024的缓冲区,默认limit=capacity,position=0
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
byteBuffer.isDirect();
// capacity:1024,limit:1024,position:0
System.out.println("1.allocate() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 2.put()方法向缓冲区写入数据,position->数据长度
byteBuffer.put("abcde".getBytes());
// capacity:1024,limit:1024,position:5
System.out.println("2.put() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 3.flip()方法切换到读取数据模式,limit->position,position->0
byteBuffer.flip();
// capacity:1024,limit:5,position:0
System.out.println("3.flip() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 4.get()读取缓冲区数据,position->已读取的长度
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
System.out.println(new String(bytes,0,bytes.length));
// capacity:1024,limit:5,position:5
System.out.println("4.get() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 5.rewind(),position->0
byteBuffer.rewind();
// capacity:1024,limit:5,position:0
System.out.println("5.rewind() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 6.mark()
byteBuffer.get(new byte[3]);
byteBuffer.mark();
// capacity:1024,limit:5,position:3
System.out.println("6.mark() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 7.hasRemaining():是否还有剩余数据
int remain = 0;
if(byteBuffer.hasRemaining()){
// 8.remaining():获取剩余数据数量
remain = byteBuffer.remaining();
// remain:2
System.out.println("7 & 8 -> remain:"+remain);
}
// 9.reset()
byteBuffer.get(new byte[remain]);
// capacity:1024,limit:5,position:5
System.out.println("9-1.before reset() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
byteBuffer.reset();
// capacity:1024,limit:5,position:3
System.out.println("9-2.after reset() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
// 10.clear():清空缓冲区,capacity、limit、position变为初始值,但数据并未清除
byteBuffer.clear();
// capacity:1024,limit:1024,position:0
System.out.println("10.clear() -> capacity:"+byteBuffer.capacity()+",limit:"+byteBuffer.limit()+",position:"+byteBuffer.position());
}
}
缓冲区分为直接缓冲区
和非直接缓冲区
,非直接缓冲区在JVM的堆(heap)内存空间分配内存地址(数据在JVM内存空间及操作系统内核的内存空间两者之间会发生复制动作),而直接缓冲区会在操作系统内核的内存空间直接分配地址作为缓冲区,避免了数据的在JVM与OS之间的复制,从而加速数据传输。
allocate()
分配的是非直接缓冲区,而分配直接缓冲区使用的方法是allocateDirect()
,另外isDirect()
方法可以判断是否为直接缓冲区。