Java的NIO入门
一、介绍
Java NIO是从Java 1.4版本开始引入的一个新的IO ,在传统的IO模型中,使用的是同步阻塞IO,也就是blocking  IO。
而NIO指的是New IO,代指新IO模型。有些博客指的是not blocking IO,非阻塞IO,叫哪种都行,都是NIO。
在NIO中,最重要的两个东西就是缓冲Buffer和通道Channel了。继续往下看!
二、Buffer
缓冲区Buffer,可以理解成是一个含数组的容器对象,该对象提供了一组方法,可以更轻松地使用其中的数据。该对象记录了一些状态值,能够跟踪和记录缓冲区的状态变化情况。
后续的通道Channel的读取、写入操作都经过缓冲。
Buffer是一个抽象类,它的实现类有很多,但我们最常用的还是ByteBuffer,因为要和字节打交道嘛

它里面有四个最重要的状态值,分别是
- 
mark:标记
 
- 
position:当前读取或存储数据的索引位置,位置
 
- 
limit:当前缓冲最大可以写入或读取到的位置,极限
 
- 
capacity:当前缓冲的容量,容量
 
其中,mark<= position<=limit<=capacity,具体是什么作用,稍等看看演示代码,建议打开java的api文档来同步进行查看
1)初识缓冲
建议DEBUG,进入后查看上面的四个状态值的变化
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | package com.banmoon.test;
 import java.nio.IntBuffer;
 
 public class BufferTest01 {
 
 public static void main(String[] args) {
 
 IntBuffer buffer = IntBuffer.allocate(5);
 
 buffer.put(1);
 buffer.put(2);
 buffer.put(3);
 buffer.put(4);
 
 
 buffer.flip();
 
 
 System.out.println(buffer.get());
 System.out.println(buffer.get());
 System.out.println(buffer.get());
 System.out.println(buffer.get());
 
 
 buffer.clear();
 }
 }
 
 | 
2)BufferUnderFlowException
BufferUnderFlowException异常,存的类型和取的类型不一致所导致的异常。
不同的类型的存储大小空间不同,所以会导致读取的异常
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | package com.banmoon.test;
 import java.nio.ByteBuffer;
 
 public class BufferTest02 {
 
 public static void main(String[] args) {
 
 ByteBuffer buffer = ByteBuffer.allocate(100);
 
 buffer.putShort((short) 1);
 buffer.putInt(1);
 buffer.putLong(100);
 
 
 buffer.flip();
 
 
 System.out.println(buffer.getLong());
 System.out.println(buffer.getFloat());
 System.out.println(buffer.getLong());
 }
 }
 
 | 

3)只读缓冲
可以将一个缓冲设置为只读,也就是说在缓冲有数据后,可以得到一个只读的缓冲,此缓冲不再支持写入。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | package com.banmoon.test;
 import java.nio.ByteBuffer;
 
 public class BufferTest03 {
 
 public static void main(String[] args) {
 
 ByteBuffer buffer = ByteBuffer.allocate(5);
 
 for (int i = 0; i < buffer.capacity(); i++) {
 buffer.put((byte) i);
 }
 
 
 buffer.flip();
 
 ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
 
 
 while (readOnlyBuffer.hasRemaining()) {
 System.out.println(readOnlyBuffer.get());
 }
 
 
 
 }
 }
 
 | 

三、Channel
Channel,称为通道,类似流,但与流有下面几点区别
- 
通道可以同时进行读写,而流只能读或者写 
- 
通道可以实现异步读写数据 
- 
通道可以从缓冲读数据,可以写入数据到缓冲 
Channel是一个接口,常用的实现类如下
- 
FileChannelImpl:文件相关的通道
 
- 
ServerSocketChannel:类似BIO中的ServerSocket,用于TCP的连接
 
- 
SocketChannel:类似BIO中的Socket,用于TCP的连接
 
- 
DatagramChannel:用于UDP数据的读写
 
多说无益,先来看看他们的使用好吧,建议打开java的api文档来同步进行查看
1)写入输出文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | package com.banmoon.test;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 
 public class ChannelTest01 {
 
 public static void main(String[] args) throws IOException {
 String str = "你好,半月无霜";
 
 FileOutputStream outputStream = new FileOutputStream("E:\\repository\\test.txt");
 
 FileChannel channel = outputStream.getChannel();
 
 ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
 
 channel.write(byteBuffer);
 
 outputStream.close();
 }
 
 }
 
 | 
2)读取指定文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | package com.banmoon.test;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 
 public class ChannelTest02 {
 
 public static void main(String[] args) throws IOException {
 File file = new File("E:\\repository\\test.txt");
 
 FileInputStream inputStream = new FileInputStream(file);
 
 FileChannel channel = inputStream.getChannel();
 
 ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
 
 channel.read(byteBuffer);
 
 System.out.println(new String(byteBuffer.array()));
 }
 
 }
 
 | 

3)拷贝文件
拷贝文件,也就是使用同一个Buffer完成读写,首先我们先准备好一个文件,我们重新创建一个文件hello.txt,如下
| 12
 3
 4
 5
 6
 
 | 你好,半月无霜!1、飞流直下三千尺,不及汪伦送我情。
 2、醒时同交欢,儿女忽成行。
 3、路漫漫其修远兮,壮士一去兮不复返!
 4、后宫佳丽三千人,铁杵磨成绣花针。
 5、问世间情为何物,两岸猿声啼不住。
 
 | 
开始拷贝啦
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 
 | package com.banmoon.test;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 
 public class ChannelTest03 {
 
 public static void main(String[] args) throws IOException {
 
 FileInputStream inputStream = new FileInputStream("E:\\repository\\hello.txt");
 
 FileChannel channel01 = inputStream.getChannel();
 
 FileOutputStream outputStream = new FileOutputStream("E:\\repository\\hello_copy.txt");
 
 FileChannel channel02 = outputStream.getChannel();
 
 
 ByteBuffer byteBuffer = ByteBuffer.allocate(16);
 
 
 while (true) {
 
 byteBuffer.clear();
 
 
 int read = channel01.read(byteBuffer);
 
 if (read == -1)
 break;
 
 
 byteBuffer.flip();
 
 
 channel02.write(byteBuffer);
 }
 
 
 inputStream.close();
 outputStream.close();
 }
 
 }
 
 | 
4)快速拷贝文件
拷贝文件,与上面不同的是,上面是自己写缓冲进行读写,这一次直接使用channel的api进行拷贝,方便快捷。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | package com.banmoon.test;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.channels.FileChannel;
 
 public class ChannelTest04 {
 
 public static void main(String[] args) throws IOException {
 
 FileInputStream inputStream = new FileInputStream("E:\\repository\\hello.txt");
 
 FileChannel channel01 = inputStream.getChannel();
 
 FileOutputStream outputStream = new FileOutputStream("E:\\repository\\hello_copy.txt");
 
 FileChannel channel02 = outputStream.getChannel();
 
 
 channel01.transferTo(0, channel01.size(), channel02);
 
 
 
 
 inputStream.close();
 outputStream.close();
 }
 
 }
 
 | 
四、最后
NIO在上面的入门示例中,完全没有展现出NIO的同步非阻塞的特点与优势,后续会开单章补上。
先简简单单入个门吧,最主要的NIO就是缓冲和通道。
我是半月,祝你幸福!!!