NIO即New IO,在之前的Java编程中,一般使用流的方式来处理IO,所有的IO都被视作单个字节的移动,通过stream对象一次移动一个字节。流IO负责把对象转换为字节,然后再转换为对象。
NIO与IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块。所以NIO的效率要比IO高。
IO是以流的方式处理数据,而NIO是以块的方式处理数据。
面向流的IO一次一个字节的处理数据,一个输入流产生一个字节,一个输出流就消费一个字节。为流式数据创建过滤器就变得非常容易,链接几个过滤器,以便对数据进行处理非常方便而简单,但是面向流的IO通常处理的很慢。
面向块的IO系统以块的形式处理数据。每一个操作都在一步中产生或消费一个数据块。按块要比按流快的多,但面向块的IO缺少了面向流IO所具有的简单性。
一个Buffer实质上是一个容器对象,发给Channel的所有对象都必须先放到Buffer中;同样的,从Channel中读取的任何数据都要读到Buffer中。
Buffer是一个对象,它包含一些要写入或读出的数据。在NIO中,数据是放入buffer对象的,而在IO中,数据是直接写入或者读到Stream对象的。应用程序不能直接对 Channel 进行读写操作,而必须通过 Buffer 来进行,即 Channel 是通过 Buffer 来读写数据的。
在NIO中,所有的数据都是用Buffer处理的,它是NIO读写数据的中转池。Buffer实质上是一个数组,通常是一个字节数据,但也可以是其他类型的数组。但一个缓冲区不仅仅是一个数组,重要的是它提供了对数据的结构化访问,而且还可以跟踪系统的读写进程。
使用 Buffer 读写数据一般遵循以下四个步骤:
1.写入数据到 Buffer;
2.调用 flip() 方法;
3.从 Buffer 中读取数据;
4.调用 clear() 方法或者 compact() 方法。
当向 Buffer 写入数据时,Buffer 会记录下写了多少数据。一旦要读取数据,需要通过 flip() 方法将 Buffer 从写模式切换到读模式。在读模式下,可以读取之前写入到 Buffer 的所有数据。
一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用 clear() 或 compact() 方法。clear() 方法会清空整个缓冲区。compact() 方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
Buffer的类型有:
capacity:代表缓冲区的最大容量,一般新建一个缓冲区的时候,limit的值和capacity的值默认是相等的。
limit:代表还有多少数据可以取出或还有多少空间可以写入,它的值小于等于capacity。
position:跟踪已经写了多少数据或读了多少数据,它指向的是下一个字节来自哪个位置
Channel是一个对象,可以通过它读取和写入数据。可以把它看做IO中的流。但是它和流相比还有一些不同:
1.Channel是双向的,既可以读又可以写,而流是单向的 2.Channel可以进行异步的读写 3.对Channel的读写必须通过buffer对象
由于所有的数据都需要通过Buffer对象处理,所以不能将字节直接写入到Channel中,需要先将数据写入到Buffer中;同样,也不能直接从Channel中直接读取字节,需要先将数据从Channel读入到Buffer,再从Buffer获取这个字节。
在Java NIO中Channel主要有如下几种类型:
- FileChannel:从文件读取数据的
- DatagramChannel:读写UDP网络协议数据
- SocketChannel:读写TCP网络协议数据
- ServerSocketChannel:可以监听TCP连接
NIO中从通道中读取:创建一个缓冲区,然后让通道读取数据到缓冲区。
NIO写入数据到通道:创建一个缓冲区,用数据填充它,然后让通道用这些数据来执行写入。
1.从FileInputStream获取Channel
2.创建Buffer
3.从Channel读取数据到Buffer
// 从文件读取数据到缓冲区 @Test public void ChannelRead() throws IOException{ // 1、获取通道 FileInputStream fin = new FileInputStream( "readandshow.txt" ); FileChannel fc = fin.getChannel(); // 2、创建缓冲区 ByteBuffer buffer = ByteBuffer.allocate( 1024 ); // 3、将数据从通道读到缓冲区 fc.read( buffer ); }
创建一个Buffer,然后从源文件读取数据到缓冲区,然后再将缓冲区写入目标文件。
// 读写操作的例子 public void copyFileUseNIO(String src,String dst) throws IOException{ //声明源文件和目标文件 FileInputStream fi=new FileInputStream(new File(src)); FileOutputStream fo=new FileOutputStream(new File(dst)); //获得传输通道channel FileChannel inChannel=fi.getChannel(); FileChannel outChannel=fo.getChannel(); //获得容器buffer ByteBuffer buffer=ByteBuffer.allocate(1024); while(true){ //判断是否读完文件 int eof =inChannel.read(buffer); if(eof==-1){ // 数据结束时,read()方法就会返回-1 break; } //重设一下buffer的position=0,limit=position buffer.flip(); //开始写 outChannel.write(buffer); //写完要重置buffer,重设position=0,limit=capacity buffer.clear(); } inChannel.close(); outChannel.close(); fi.close(); fo.close(); }
转载参考自:
https://www.cnblogs.com/zailushang1996/p/8916017.html