前言
下面部分内容参考 Java NIO 系列教程-并发编程网
NIO类库简介
NIO 库是在JDK 1.4中引入的,NIO 弥补了原来同步阻塞 I/O 的不足,它在标准Java代码中提供了高速的,面向块的I/O。NIO的核心部分主要有:
- 通道 Channel
- 缓冲区 Buffer
- 多路复用器 Selector
下面一一介绍着三大核心部分。
通道 Channel
Channel 是一个通道,它就像自来水管一样,网络数据通过 Channel 读取和写入。
通道与流的不同之处在于:
- 通道是双向的,既可以从通道中读取数据,也可以写数据到通道,而流的读写通常是单向的,它只是在一个方向上移动
- 通道可以异步地读写
- 通道中的数据总是要先读到一个缓冲区Buffer,或者总是要从一个 Buffer 中写入
Channel的实现
Channel本质是一个接口,它在有很多重要的实现
- FileChannel
FileChannel从文件中读取数据,也可以将数据写到文件中,FileChannel无法设置非阻塞模式,它总是运行在阻塞模式下。
- DatagramChannel
DatagramChannel通过UDP读写网络中的数据
- SocketChannel
SocketChannel通过TCP读写网络中的数据
- ServerSocketChannel
可以监听新进来的TCP连接,像 Web 服务器那样,对每一个新进来的连接都会创建一个SocketChannel。
SocketChannel和ServerSocketChannel 就对应 传统网络编程中的 Socket类和ServerSocket类
Channel的例子
下面以 FileChannel为例来写一个关于通道与缓冲区的例子,代码如下:
public class ChannelTest {
public static void main(String[] args) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile("C:\\Users\\Administrator\\Desktop\\nio-data.txt", "rw");
//打开FileChannel
FileChannel fileChannel = accessFile.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
//从通道里读取数据到缓冲区
int bytesRead = fileChannel.read(byteBuffer);
while (bytesRead != -1) {
System.out.println("Read: "+bytesRead);
//反转
byteBuffer.flip();
//从缓冲区中读取数据
while (byteBuffer.hasRemaining()) {
System.out.print((char)byteBuffer.get());
}
byteBuffer.clear();
bytesRead = fileChannel.read(byteBuffer);
}
accessFile.close();
}
}
- 在使用 FileChannel 之前,必须先打开它,我们无法直接打开它,需要通过一个InputStream,OutputStream或者RandomAccessFile 来打开它
- 从 FileChannel 中读取数据,先分配一个Buffer(关于Buffer的介绍参见下文),调用 FileChannel 的read()方法,该方法返回的 int 值表示了有多少字节被读到了 Buffer 中
缓冲区 Buffer
在NIO库中,数据是从通道读入到缓冲区,从缓冲区写入到通道中的。
缓冲区本质上是一块可以写入的数据,然后可以从读取数据的内存。这块内存被封装成了 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。
Buffer的类型
Java NIO有以下几种Buffer 类型
- ByteBuffer: 字节缓冲区
- MappedByteBuffer: 用于实现内存映射文件
- CharBuffer: 字符缓冲区
- ShortBuffer: 短整型缓冲区
- IntBuffer: 整型缓冲区
- LongBuffer: 长整形缓冲区
- FloatBuffer: 浮点型缓冲区
- DoubleBuffer: 双精度浮点型缓冲区
Buffer的内部属性
缓冲区Buffer 内部就是用数组实现的。Buffer 包含了下面4个属性:
- Capacity (容量)
缓冲区能够容纳的数据元素的最大数量。这个容量在缓冲区创建时被设定,并且永远不会被改变。你只能往里写 capacity 个 byte,long,char等类型。一旦 Buffer 满了,需要将其清空 (通过读数据或者清除数据) 才能往里写数据
Limit (上界)
缓冲区的第一个不能被读或写的元素,或者说缓冲区现存元素的上界。在写模式下,Buffer的limit 表示最多能往 Buffer 里写多少数据。写模式下,limit 等于 Buffer 的capacity。当切换Buffer到读模式,limit表示你最多能读到多少数据。此时limit会被设置成写模式下的position值。
Position (位置)
缓冲区内下一个将要被读或写的元素位置,在进行读写缓冲区时,位置为自动更新。当你写数