一、NIO是个啥?
- 同步非阻塞
- 有三个核心组件:
- Channel:通道
- Buffer:缓冲区
- Selector:选择器
- 非阻塞,我理解是啥?
- NIO对于缓冲区的读写是双向的,这个是有别于BIO的;同时,NIO在操作或者写操作后,需要使用flip方法进行切换。
package com.angliali.nio;
import java.nio.IntBuffer;
public class BasicBuffer {
public static void main(String[] args) {
//初始化一个大小为5的缓冲区
IntBuffer intBuffer = IntBuffer.allocate(5);
//向缓冲区中防止元素
for (int i = 0 ;i<5;i++ ){
intBuffer.put(i);
}
//从缓冲器中读取元素
intBuffer.flip();
while (intBuffer.hasRemaining()){
System.out.println(intBuffer.get());
}
}
}
- NIO的模型通过画图进行说明。
二、缓冲区Buffer
- 本质上是一个读写的内存块
- 从源码的角度分析
看下缓冲区的父类
public abstract class Buffer {
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;//标识符
private int position = 0;//表示下一次读写的位置下表
private int limit;//表示缓冲区当前的重点,不能去操作超过重点的位置
private int capacity;//容量,表示缓存区的大小
。。。
}
在子类中,元素都是存储在一个数组中。
public abstract class IntBuffer
extends Buffer
implements Comparable<IntBuffer>
{
final int[] hb; // Non-null only for heap buffers,实际用来存储元素的数组
final int offset;
boolean isReadOnly; // Valid only for heap buffers
}
三、通道Channel
- 通道类似流,可以对通道进行读写操作,上面的图也能看出来
- Channel是个接口,源码
public interface Channel extends Closeable {
public boolean isOpen();
public void close() throws IOException;
}
- 常用的实现类有:FileChannel、ServerSocketChannel、SocketChannel和DatagramChannel由于udp数据的读写
- 特别介绍下FileChannel
public abstract class FileChannel
extends AbstractInterruptibleChannel
implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
{
//read方法是将通读的数据存放到缓冲区
public abstract int read(ByteBuffer dst) throws IOException;
//write方法是将缓冲区的数据写到通道
public abstract int write(ByteBuffer src) throws IOException;
}
下面我写了一下例子:
例子1:使用nio把数据写到文件里面
package com.angliali.nio;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NioFileChannel {
public static void main(String[] args) throws IOException {
String str = "hello";
//使用nio把字符串写入到文件:H:\book\md\NIOChannel.txt
//实现缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.put(str.getBytes());
byteBuffer.flip();
//实现通道
FileOutputStream fileOutputStream = new FileOutputStream("H:\\book\\md\\NIOChannel.txt");
FileChannel fileChannel = fileOutputStream.getChannel();
//完成缓冲区写入到通道
fileChannel.write(byteBuffer);
//关闭流
fileOutputStream.close();
}
}
例子2:使用nio将文件内容输出到控制台
package com.angliali.nio;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/*
使用nio,将文件:H:\book\md\NIOChannel.txt 内容读出到控制台
*/
public class NioFileChannelRead {
public static void main(String[] args) throws IOException {
//创建文件的输入流
FileInputStream fileInputStream = new FileInputStream("H:\\book\\md\\NIOChannel.txt");
//获得通道
FileChannel fileChannel = fileInputStream.getChannel();
//获得缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
//将通道中的数据写入到缓冲区
fileChannel.read(byteBuffer);
byteBuffer.flip();
System.out.println(new String(byteBuffer.array()));
fileInputStream.close();
}
}
例子3:使用一个缓冲区完成两个文件内容的拷贝
package com.angliali.nio;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/*
使用一个缓冲完成文件1到文件2的内容的拷贝
*/
public class NioFileChannelFileCopy {
public static void main(String[] args) throws IOException {
//输入流
FileInputStream fileInputStream = new FileInputStream("H:\\book\\md\\NIOChannel.txt");
//输出流
FileOutputStream fileOutputStream = new FileOutputStream("H:\\book\\md\\1.txt");
//获得通道
FileChannel channelRead = fileInputStream.getChannel();
FileChannel channelWrite = fileOutputStream.getChannel();
//缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//将文件1的通道内容写入到缓冲区
while(true){
byteBuffer.clear();
int length = channelRead.read(byteBuffer);
if(length == -1){
break;
}
byteBuffer.flip();
//将缓冲区的内容写入到通道2
channelWrite.write(byteBuffer);
}
}
}
- 还有一个重要的概念就是分散和聚集,理解起来就是,我们可以使用一个缓冲区的数组去处理请求,在使用时,会去一次填满缓冲区