NIO流基础

本文详细介绍了Java NIO(非阻塞I/O)与传统的IO的区别,强调了NIO的块处理方式和效率优势。NIO引入了通道(Channel)和缓冲区(Buffer)的概念,通道是双向的,而流是单向的。缓冲区在读写过程中起关键作用,提供了一种更有效的方式处理数据。此外,NIO的事件选择器允许非阻塞读取,提高了并发处理能力。文章还给出了NIO读写文件和进行文件拷贝的示例代码。
摘要由CSDN通过智能技术生成

1.nio与io的区别

  • NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式一次一个字节地去写入和读出的。所以在效率上的话,肯定是NIO效率比IO效率会高出很多。

  • NIO不在是和IO一样用OutputStream和InputStream 输入流的形式来进行处理数据的,但是又是基于这种流的形式,而是采用了通道和缓冲区的形式来进行处理数据的。

  • NIO的通道是可以双向的,但是IO中的流只能是单向的

2.Channel

  • Channel,国内大多翻译成“通道”。Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件

3.Buffer

  • Buffer是一个缓冲区实质上是一个数组,用于和NIO通道FileChannel进行交互。

  • 在 I/O 中,将数据直接写入或者将数据直接读到 Stream 对象中。

    • 在 NIO 库中,所有数据都是用Buffer 缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。

1.nio与io的区别

  • NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式一次一个字节地去写入和读出的。所以在效率上的话,肯定是NIO效率比IO效率会高出很多。

  • NIO不在是和IO一样用OutputStream和InputStream 输入流的形式来进行处理数据的,但是又是基于这种流的形式,而是采用了通道和缓冲区的形式来进行处理数据的。

  • NIO的通道是可以双向的,但是IO中的流只能是单向的

2.Channel

  • Channel,国内大多翻译成“通道”。Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件

3.Buffer

  • Buffer是一个缓冲区实质上是一个数组,用于和NIO通道FileChannel进行交互。

  • 在 I/O 中,将数据直接写入或者将数据直接读到 Stream 对象中。

  • 在 NIO 库中,所有数据都是用Buffer 缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。

 

 案例:

package nio;

import java.nio.ByteBuffer;

public class FileWriterWithNIO {
    public void FileWriteNIO(){
        //创建ByteBuffer对象
        ByteBuffer buffer=ByteBuffer.allocate(11);
        //buffer写入参数
        buffer.put("hello".getBytes());
//        打印buffer相关参数
        System.out.printf("capacity:%s,limit:%s,position:%s\n",buffer.capacity(),buffer.limit(), buffer.position());
        System.out.println("========================================");
        //flip
        //positoin位置归0
        buffer.flip();
        System.out.printf("capacity:%s,limit:%s,position:%s\n",buffer.capacity(),buffer.limit(), buffer.position());
        byte[] array=buffer.array();
        String s=new String(array,0,buffer.limit());
        System.out.println(s);

    }
    public void readWriteNIO(){
        ByteBuffer buffer= ByteBuffer.allocate(11);
        buffer.put("hello".getBytes());
        System.out.printf("capacity:%s,limit:%s,position:%s\n",buffer.capacity(),buffer.limit(), buffer.position());
        System.out.println("====position归0---------");
        //position归零limit得值就是position原来的值
        buffer.flip();
        //从零开始的,limit是最后元素的下一位的位置(下标)
        System.out.printf("capacity:%s,limit:%s,position:%s\n",buffer.capacity(),buffer.limit(), buffer.position());
        System.out.println("======================");
        for (int i = 0; i <buffer.limit() ; i++) {
            System.out.print((char) buffer.get(i));
        }


    }

    public static void main(String[] args) {
        new FileWriterWithNIO().FileWriteNIO();
        new FileWriterWithNIO().readWriteNIO();
    }
}

 

 

4.Channel与Buffer一起使用

  • FileChannel和Buffer一起用的步骤

  • 使用FileChannel之前,必须先打开它。(但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例)

    • FileChannel类里的方法:

用完FileChannel后必须将其关闭:

案例 :

package nio;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ReadWriterWiterNIO{
    public static void main(String[] args) throws IOException {
        FileInputStream fis=null;
        FileChannel fc=null;
        //创建FileIInputStream对象
        fis=new FileInputStream("data.txt");
        //打开channel通道
        fc=fis.getChannel();
        //定义ByteBuffer对象
        ByteBuffer buffer=ByteBuffer.allocate(2);
        int len;
        //边读边输出字符
        int byesRead=fc.read(buffer);
        System.out.println("读到了"+byesRead);
        while((len=fc.read(buffer))!=-1){
            //position归0
            buffer.flip();
            //判断是否有值
            while(buffer.hasRemaining()){
                //buffer.get() 取position位置的字节值,然后增加position的值,移动一位直到和limit相重合
                byte b=buffer.get();
                System.out.print((char)b);
            }
            //让position归0,不然无法再往buffer添加数据造成死循环
  //clear和flip一样 一开始将数据存在缓存区中 将原本的数据清空
            //不用filp数据读不进去
//            buffer.clear();
            buffer.flip();
        }
        fis.close();
        fc.close();




    }


}

利用NIO进行文件拷贝(也可拷贝部分数据)的示例: 、

package nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class TestFileCopyWithNIO {
    public static void main(String[] args) throws IOException {
        //创建文件输入流FileInputStream
        FileInputStream fis = new FileInputStream("data.txt");
        //创建文件输出流FileOutputStream
        FileOutputStream fos=new FileOutputStream("data1.txt");
        //打开输入通道
        FileChannel inChannel=fis.getChannel();
        // 打开输出通道
        FileChannel outChannel=fos.getChannel();
//    transferTO把输入流通道数据转移到输出流通道中
        inChannel.transferTo(0,inChannel.size(),outChannel);
        inChannel.close();
        outChannel.close();
        fis.close();
        fos.close();
    }


}

 

5.事件及nio的非阻塞读取

  • Java NIO的事件选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道

  • 由于有了事件选择器,因此NIO可以以非阻塞的方式读取数据

  • NIO的这些特性在网络通讯方面非常有用。

 

6.NIO和IO的区别

 Java NIO和IO的主要区别、

 

  • 面向Stream和面向Buffer

    • Java NIO和IO之间最大的区别是IO是面向流(Stream)的,NIO是面向块(buffer)的。

    • 面向流意味着从流中一次可以读取一个或多个字节,拿到读取的这些做什么你说了算,这里没有任何缓存(这里指的是使用流没有任何缓存,接收或者发送的数据是缓存到操作系统中的,流就像一根水管从操作系统的缓存中读取数据)而且只能顺序从流中读取数据,如果需要跳过一些字节或者再读取已经读过的字节,你必须将从流中读取的数据先缓存起来。

    • 面向块的处理方式有些不同,数据是先被读/写到buffer中的,根据需要你可以控制读取什么位置的数据。这在处理的过程中给用户多了一些灵活性,你需要额外做的工作是检查你需要的数据是否已经全部到了buffer中,你还需要保证当有更多的数据进入buffer中时,buffer中未处理的数据不会被覆盖。

  • 阻塞IO和非阻塞IO

    • 所有的Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞知道读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情

    • java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行

  • Selectors

    Java NIO的selectors允许一条线程去监控多个channels的输入,你可以向一个selector上注册多个channel,然后调用selector的select()方法判断是否有新的连接进来或者已经在selector上注册时channel是否有数据进入。selector的机制让一个线程管理多个channel变得简单。

 IO适合大量数据传输时,当你的数据量大时,它都可以传输,但是速度慢,但是数据不会丢失,它是面向流的

NIO是以块的形式去处理数据,适合繁琐但是大小不大的数据量传输,比如你虽然有很多个文件夹但是它们的内容少,它的快,它会放入缓存buffer中,当他的buffer满时,它的数据可能会丢失。

因为NIO通过通道去传输,它是双向的

而IO是单向的

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值