一、什么是nio
1.NIO是一个可以替代标准Java IO API的IO API(从Java 1.4开始),NIO提供了与标准IO不同的IO工作方式,NIO: Channels and Buffers(通道和缓冲区)
二、nio与io的对比
IO |
NIO |
面向流 |
面向缓冲区 |
阻塞IO |
非阻塞IO |
无 |
选择器 |
三、buffer的数据存取
1.Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入到缓冲区,从缓冲区写入通道中的,Buffer就像一个数组,可以保存多个相同类型的数据。根据类型不同(boolean除外),有以下Buffer常用子类:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
2.buffer的概述
1)容量(capacity):表示Buffer最大数据容量,缓冲区容量不能为负,并且建立后不能修改。
2)限制(limit):第一个不应该读取或者写入的数据的索引,即位于limit后的数据不可以读写。缓冲区的限制不能为负,并且不能大于其容量(capacity)。
3)位置(position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制(limit)。
4)标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。
3.代码
/**
* (缓冲区)buffer 用于NIO存储数据 支持多种不同的数据类型 <br>
* 1.byteBuffer <br>
* 2.charBuffer <br>
* 3.shortBuffer<br>
* 4.IntBuffer<br>
* 5.LongBuffer<br>
* 6.FloatBuffer <br>
* 7.DubooBuffer <br>
* 上述缓冲区管理的方式 几乎<br>
* 通过allocate() 获取缓冲区 <br>
* 二、缓冲区核心的方法 put 存入数据到缓冲区 get <br> 获取缓冲区数据 flip 开启读模式
* 三、缓冲区四个核心属性<br>
* capacity:缓冲区最大容量,一旦声明不能改变。 limit:界面(缓冲区可以操作的数据大小) limit后面的数据不能读写。
* position:缓冲区正在操作的位置
*/
public class test001 {
public static void main(String[] args) {
//1.指定缓冲区的大小1024
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
System.out.println("-------------------");
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
// 2.向缓冲区存放5个数据
byteBuffer.put("abcd1".getBytes());
System.out.println("--------------------");
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
// 3.开启读模式
byteBuffer.flip();
System.out.println("----------开启读模式...----------");
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
System.out.println(new String(bytes, 0, bytes.length));
System.out.println("----------重复读模式...----------");
byteBuffer.rewind();
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
byte[] bytes2 = new byte[byteBuffer.limit()];
byteBuffer.get(bytes2);
System.out.println(new String(bytes2, 0, bytes2.length));
// 5.clean 清空缓冲区 数据依然存在,只不过数据被遗忘
System.out.println("----------清空缓冲区...----------");
byteBuffer.clear();
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println((char)byteBuffer.get());
}
}
4.结果
-------------------
0
1024
1024
--------------------
5
1024
1024
----------开启读模式...----------
0
5
1024
abcd1
----------重复读模式...----------
0
5
1024
abcd1
----------清空缓冲区...----------
0
1024
1024
a
5.分析
5.1.这一步其实是当我们刚开始初始化这个buffer数组的时候,开始默认是这样的
5.2.但是当你往buffer数组中开始写入的时候几个字节的时候就会变成下面的图,position会移动你数据的结束的下一个位置.
5.3.这个时候你需要把buffer中的数据写到channel管道中,所以此时我们就需要用这个byteBuffer.flip()方法,当你调用完这个方法时,这个时候就会变成下面的图了,这样的话其实就可以知道你刚刚写到buffer中的数据是在position---->limit之间(重复读结果是一样的)。
5.4.这时底层操作系统就可以从缓冲区中正确读取这 5 个字节数据发送出去了。在下一次写数据之前我们在调一下 clear() 方法。缓冲区的索引状态又回到初始位置。
四、make与rest的用法
1.标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。
2.代码
public class Test002 {
public static void main(String[] args) {
ByteBuffer buf = ByteBuffer.allocate(1024);
String str = "abcd1";
buf.put(str.getBytes());
// 开启读取模式
buf.flip();
byte[] dst = new byte[buf.limit()];
buf.get(dst, 0, 2);
buf.mark();
System.out.println(new String(dst, 0, 2));
System.out.println(buf.position());
System.out.println("---------------------------");
buf.get(dst, 2, 2);
System.out.println(new String(dst, 2, 2));
System.out.println(buf.position());
buf.reset();
System.out.println("重置恢复到mark位置..");
System.out.println(buf.position());
}
}
3.结果
ab
2
---------------------------
cd
4
重置恢复到mark位置..
2
五、结束
1.下篇继续讲解java基础之nio编程的直接缓冲区与非直接缓冲区的区别以及安全性。Always keep the faith!!!