NIO概述
为什么了有了IO,还需要有NIO?
* NIO在JDK1.4后引入的
* NIO是面向块(缓冲区)编程,旧IO是面向流编程
*
* IO NIO
* 面向流 面向缓冲区
* 阻塞IO 非阻塞IO
* 无 选择器
*
* Java中针对IO的一些核心的包和接口、类
*
* java.nio 主要包含了各种与Buffer相关的类
* java.nio.channel 主要包含了与Channel和Selector相关的类和接口
* java.nio.charset 主要包含了与编码相关的类接口
* java.nio.channels.spi 主要包含了与Channel相关的服务提供者编程接口
* javan.nio.charset.spi 主要包含了与charset相关的服务提供者编程接口
*
*
* 目前需要掌握的核心就是三个包
* Buffer
* Channel
* CharSet
*
* 面向缓冲区编程:
* 数据的读写必须经过缓冲区
* 我们可以使用Buffer所对应的子类来数据从通道(Channel)流向缓冲区
* 从缓冲区写到通道叫做读取缓冲区
Buffer缓冲区
Buffer
* Buffer是一个抽象类
* 子类有
* ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer
*
* 核心类
* ByteBuffer和CharBuffer
* ByteBuffer有一个子类 MappedByteBuffer
* MappedByteBuffer类能够将文件直接映射到内存中,那么这样我们就可以像访问内存一样访问文件,非常方便
*
* 获取Buffer
* 获取ByteBuffer
* static ByteBuffer allocate(int capacity)
分配一个新的字节缓冲区。
static ByteBuffer allocateDirect(int capacity)
分配新的直接字节缓冲区。
二者获取Buffer的区别
1.创建普通Buffer成本低,读写的效率不高
2.因为创建直接Buffer成本高,所以我们一般用在Buffer生存周期较长的时候使用
3.只有ByteBuffer才能够创建直接Buffer,其他的Buffer对象是不能够创建
4.如果创建了直接Buffer但是我又想要使用其他Buffer的功能,可以将ByteBuffer转换成其他Buffer
asIntBuffer()
* 四个非常重要的概念
* capacity: 缓冲区的容量,不可以为负数,一旦创建了就不能够改变
* limit: 无效缓冲区的第一个位置索引,limit后面的数据既不可读,也不可写
* position : 下一个可以被读取或者写入的缓冲区位置索引
* mark: 标记索引,该索引能够用于下次读取或者写入,它只能够在0-position之间
*
* 四个系数的关系:
* 0 < mark < postion < limit < capacity
*
* 五个方法
* flip(): 将写模式切换为读模式, 将limit的值改为postion的值,同时将postion归0
* 特点: 就是为下一次数据的读取做好准备
* clear(): 将读模式切换为写模式,将limit改为capacity的值,同时将postion归0
* 特点: 就是为下一次数据的写入做好准备
* put(): 相对读取,向Buffer中存储数据
* get(): 相对读取,从Buffer中获取数据
* hasRemaining(): 判断当前位置和limit之间是否还有元素可处理
*
* 绝对读取: get(index) 不会影响position的位置
* 相对读取: put() get() 会影响,每次读取一次,指针后移
*/
public class NIODemo02 {
public static void main(String[] args) {
// ByteBuffer buffer = ByteBuffer.allocate(5);
// ByteBuffer buffer2 = ByteBuffer.allocateDirect(10);
CharBuffer buffer = CharBuffer.allocate(8);
// Buffer已经准备好了向Buffer中写数据 写模式
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 0
buffer.put('a');
buffer.put('b');
buffer.put('c');
System.out.println("------------------------");
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 3
System.out.println("------------------------");
// 切换模式 ,limit变为position的位置然后将position变为0
buffer.flip();
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 3
System.out.println("position:" + buffer.position()); // 0
System.out.println("------------------------");
// char ch = 0;
// ch = buffer.get();
// System.out.println(ch);
// ch = buffer.get();
// System.out.println(ch);
//
//// System.out.println("capacity:" + buffer.capacity()); // 8
//// System.out.println("limit:" + buffer.limit()); // 3
//// System.out.println("position:" + buffer.position()); // 2
// ch = buffer.get();
// System.out.println(ch);
//
// ch = buffer.get();
// System.out.println(ch);
int ch = 0;
while (buffer.hasRemaining()) {
ch = buffer.get();
System.out.println((char)ch);
}
System.out.println("------------------");
buffer.clear(); // 将postion 清 0 ,将limit = capacity
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 0
// 注意: 调用clear方法只是将读模式改为写模式,并不会清空缓冲区的数据
System.out.println(buffer.get(1));
System.out.println("执行绝对读取之后Buffer的position位置:" + buffer.position());
}
}
Channel通道
* Channel原理类似于传统的流对象, FileInputStream FileOutputStream
* 但是有两个主要的区别
* 1.Channel能够将指定的部分或者全部文件映射到内存中
* 全部映射
* MappedByteBuffer
* 部分文件映射
* 2.程序如果想要读取Channel中的数据,不能够直接读写,必须经过Buffer
*
* Java中为Channel提供了如下常用的类
*
* FileChannel 和文件相关的通道
* DatagramChannel 和UDP协议传输数据相关的通道
* SocketChannel 和TCP协议相关的数据传输通道
* ServerSocket 和TCP协议相关的数据传输通道
*
* 获取FileChannel对象
* 和文件相关的普通流有哪些?
* FileInputStream FileOutputStream RandomAccessFile
* 常用的方法
* read() : 将Channel中的数据读取到Buffer中
* write() : 向Buffer中写入数据
* map(): 将channel中的数据全部或者部分映射到Buffer中
* inChannel.map(mode, position, size)
* MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
*/
CharSet字符集
Charset 理解为现实生活的编码表对象
*/
public class NIODemo05 {
public static void main(String[] args) throws CharacterCodingException {
// 获取当前JDK所支持的所有编码类型
// SortedMap<String, Charset> map = Charset.availableCharsets();
//
// for (String key : map.keySet()) {
// Charset charset = map.get(key);
// System.out.println(charset);
// }
// 知道了对应JDK认可的字符集别名后,那么我们就可以来获取对应的字符集对象
Charset charset = Charset.forName("GBK");
// 创建编码器 编码 字符/字符串/字符数组 --> 字节
CharsetEncoder encoder = charset.newEncoder();
// 创建解码器 解码 上述相反
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = CharBuffer.allocate(10);
charBuffer.put("abc");
charBuffer.flip();
ByteBuffer byteBuffer = encoder.encode(charBuffer);
for (int i = 0; i < byteBuffer.limit(); i++) {
System.out.println(byteBuffer.get(i));
}
System.out.println(decoder.decode(byteBuffer));
}
}