NIO 1: jsr51, jdk 1.4的时候引入
NIO1
NIO2: jsr 203
JDK 7的时候引入
NIO2的时候引入了异步 io ,也就是 Asynchronous IO
java bio 是面向流的,没有缓存区的,属于阻塞IO
nio 是面向缓冲区的, 有一个 selectors选择器的概念
NIO 3大核心组件
- buffer
- channel
- selector
java nio 复杂的地方就是 读写模式混合在一起了,放到了一个数组里面
通过 flip 操作 进行读写操作 的切换
java NIO 有一个概念,就是 通过 JNI 直接申请一块堆外内存操作
实际上是调用了 C++ 的 mallocate来分配了内存,因此这种没办法被虚拟机回收,因为是堆外内存
因为用了直接内存,所有减少了数据拷贝的操作
实例代码
public class MainTest1 {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("D:\\模板\\nio\\nio\\src\\main\\resources\\a.txt");
// File file;
FileOutputStream out = new FileOutputStream("D:\\模板\\nio\\nio\\src\\main\\resources\\b.txt");
FileChannel fin = in.getChannel();
FileChannel fout = out.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
buffer.clear();
int flag = fin.read(buffer);
if (flag == -1) {
break;
}
buffer.flip();
fout.write(buffer);
}
in.close();
out.close();
}
}
public static void main(String[] args) throws IOException {
FileChannel in = FileChannel.open(Paths.get(("D:\\ASUS\\Desktop\\后台管理模板\\nio\\nio\\src\\main\\resources\\a.txt")), StandardOpenOption.READ);
// File file;
FileChannel out = FileChannel.open(Paths.get(("D:\\ASUS\\Desktop\\后台管理模板\\nio\\nio\\src\\main\\resources\\b.txt")),StandardOpenOption.WRITE);
out.transferFrom(in,0,in.size());
}
下面是 基于 nio的 echo server的简单实现
public class ServerTest2 {
public static void main(String[] args) throws Exception {
ServerSocketChannel ch = ServerSocketChannel.open();
ch.configureBlocking(false);
ch.bind(new InetSocketAddress(8888));
Selector selector = Selector.open();
ch.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
//遍历所有注册的选择键
while (it.hasNext()) {
SelectionKey k = it.next();//获取准备就绪的事件
if (k.isAcceptable()) {
System.out.println("accept");
SocketChannel cli = ch.accept();
//切换客户端为非阻塞模式
cli.configureBlocking(false);
//将通道注册到这个选择器上
cli.register(selector, SelectionKey.OP_READ);
} else if (k.isReadable()) {
// System.out.println("read ..");
//可以接收事件
//获取选择器上可以读的通道
SocketChannel cl = (SocketChannel) k.channel();
ByteBuffer bf = ByteBuffer.allocate(1024);
int f = 0;
while ((f=cl.read(bf))>0) {
System.out.println("read .");
bf.flip();
System.out.println(new String(bf.array(),0,f));
bf.clear();
}
}
it.remove();//取消选择键
}
}
}
}
public class MainTest1 {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("127.0.0.1",8888)
);
socketChannel.configureBlocking(false);
ByteBuffer bf = ByteBuffer.allocate(1024);
bf.put(new Date().toString().getBytes());
//切换成都模式
bf.flip();
//将数据写入
socketChannel.write(bf);
bf.clear();
socketChannel.close();
}
}
下面是基于UDP 的写法
public static void main(String[] args) throws IOException {
// SocketChannel socketChannel = SocketChannel.open(
// new InetSocketAddress("127.0.0.1",8888)
// );
DatagramChannel socketChannel = DatagramChannel.open();
socketChannel.configureBlocking(false);
ByteBuffer bf = ByteBuffer.allocate(1024);
bf.put(new Date().toString().getBytes());
//切换成都模式
bf.flip();
//将数据写入
socketChannel.write(bf);
bf.clear();
socketChannel.close();
}