一,Java NIO: NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块(缓冲区),所以NIO的效率要比IO高很多。
Java NIO的核心API中提供了Channel,Buffer,和Selector三个重要对象;
二:传统Io与NIO的区别:
- 在传输效率上:
传统IO是面向流的传输方式, 一次一个字节的处理数据,一个输入流产生一个字节,一个输出流就消费一个字节。虽然也有相对应的缓冲区过滤器,但并不是一种提高IO效率的措施,而NIO是以缓冲区作为传输数据的基本单位块,所有对数据的操作都是基于移进/移除缓冲区而实现的,所以在效率上,NIO效率较高;
- 阻塞与非阻塞;
传统的IO为阻塞IO,当一个线程调用read()或writer()时,该线程被阻塞,直到有一些数据被读取,或者完全写入,此期间线程不能干任何事,
而NIO为非阻塞IO,一个线程请求写入一些数据到某通道,但不需要等待他完全写入,此期间,这个线程可以去做别的事情(线程通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作,所以一个单独的线程可以管理多个输入和输出通道)
- JavaNIO中核心API
- Channel:类似与IO中的流,但是IO中的流是单向的,例如:InoutStream,OutputStream一个流只能对应一个输入或者输出的操作,而NIO中的Channel是双向的,既可以用来进行读操作,也可以用来写操作; 任何来源和目的数据都必须通过一个Channel对象。一个Buffer实质上是一个容器对象,发给Channel的所有对象都必须先放到Buffer中;同样的,从Channel中读取的任何数据都要读到Buffer中。
而NIO中Channel的常用的实现有:
FIleChannelà从文件读取数据的
DatagramChannelà读写UDP网络协议数据
SocketChannelà读写TCP网络协议数据
ServerSocketChannelà可以监听TCP连接
(2)Buffer: Buffer是一个对象,它包含一些要写入或读出的数据。在NIO中,数据是放入buffer对象的,而在IO中,数据是直接写入或者读到Stream对象的。应用程序不能直接对 Channel 进行读写操作,而必须通过 Buffer 来进行,即 Channel 是通过 Buffer 来读写数据的。
在NIO中,所有的数据都是用Buffer处理的,它是NIO读写数据的中转池。Buffer实质上是一个数组,通常是一个字节数据,但也可以是其他类型的数组。但一个缓冲区不仅仅是一个数组,重要的是它提供了对数据的结构化访问,而且还可以跟踪系统的读写进程。
在NIO中主要有八种缓冲区类(其中MappedByteBuffer是专门用于内存映射的一种ByteBuffer):
Buffer的重要方法:
Flip():翻转就是将一个处于存数据状态的缓冲区变为一个处于准备取数据的状态,使用flip()方式实现翻转。
(3)Selector: Selector是一个对象,它可以注册到很多个Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写。这样,通过一个线程管理多个Channel,就可以处理大量网络连接了。适用于网络编程IO
使用selector监听多个Channel的开发步骤:
a,创建一个Selector对象;
Selector selector = Selector.open();
b,注册Channel到Selector上, 通过调用 channel.register
()
方法来实现注册:
channel.configureBlocking(false);
SelectionKey key =channel.register(selector,SelectionKey.OP_READ);
#注册的Channel 必须设置成异步模式 才可以,,否则异步IO就无法工作,这就意味着我们不能把一个FileChannel注册到Selector,因为FileChannel没有异步模式,但是网络编程中的SocketChannel是可以的。
- 使用NIO进行文件复制
package com.deng.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/*
* 使用NIO来进行复制文件
* */
public class CopyFIle {
public static void main(String[] args) throws Exception {
String sourceStr="D:/product.xml";
String endStr="test.xml";
copyFileUseNIO(sourceStr,endStr);
}
private static void copyFileUseNIO(String sourceStr, String endStr) throws Exception {
//封装数据源和目的地
FileInputStream inFile=new FileInputStream(sourceStr);
FileOutputStream outFIle=new FileOutputStream(endStr);
//获取对应的额Channel
FileChannel inChannel = inFile.getChannel();
FileChannel outChannel = outFIle.getChannel();
//创建Buffer对象
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true) {
//判断是否读完文件
int i = inChannel.read(buffer);
if(i==-1) {
break;
}
//重设一下Buffer的position=0,limit=position,进行缓冲区反转
buffer.flip();
//开始向缓冲区中写数据
outChannel.write(buffer);
//写完要重置buffer,重设position=0,limit=capacity
buffer.clear();
}
//关闭流资源
inChannel.close();
outChannel.close();
inFile.close();
outFIle.close();
}
}