zoukankan      html  css  js  c++  java
  • NIO

    1.Java  NIO简介

        Java NIO(New IO Non Blocking IO)是从Java1.4版本开始引入的一个新的IO AIPI,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

    三次握手才建立链接流通道

    2.Java  NIO与IO的主要区别

     传统的IO流

    3.Java  缓冲区(Buffer)和通道(Channel)

        Java NIO系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到IO设备(例如:文件、套接字)的连接。若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。

    简而言之,Channel负责传输,Buffer负责存储。

     缓冲区(Buffer)

         缓冲区Buffer):一个用于特定基本数据类型的容器。有java.nio包定义的,所有缓冲区都是Buffer抽象类的子类。

        Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道的。

        一、缓冲区(Buffer):在Java NIO中负责数据的存取,缓冲区就是数组,用于存储不同数据类型的数据

    根据数据类型不同(boolean除外),提供了相应类型的缓冲区

    ByteBuffer

    CharBuffer

    shortBuffer

    IntBuffer
    LongBuffer

    FloatBuffer

    DoubleBuffer

     上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区

        二、缓冲区存取数据的两个核心方法: put():存入数据到缓冲区中 get():获取缓冲区中的数据

        四、缓冲区的四个核心属性: capacity:容量,表示缓冲区中最大存储数据容量。一旦声明不能改变。
     limit:界限,表示缓冲区中可以操作数据的大小。(limit 后数据不能进行读写)

     position<=limit<=capacity

    步骤一:开始是空的;

     步骤二:put()数据模式;

     步骤三:flip()读数据模式

    String str = "abcde";
    
            // 1.分配一个指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);
    
            System.out.println("---------allocate()---------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

    结果为

    // 2.利用put()存入数据到缓冲区中
            buf.put(str.getBytes());
    
            System.out.println("--------put()--------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

     结果为

     

    // 3.切换成读取数据模式
            buf.flip();
    
            System.out.println("--------flip()--------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

     结果为

    // 4.利用get()读取缓冲区中的数量
            byte[] dst = new byte[buf.limit()];
            buf.get(dst);
            System.out.println(new String(dst, 0, dst.length));
    
            System.out.println("----------get()------------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

     结果为

    // 5.rewind(): 可重复读
            buf.rewind();
    
            System.out.println("----------rewind()------------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

     结果为

    // 6.clear() 清空缓冲区
            buf.clear();
    
            System.out.println("----------clear()------------");
            System.out.println(buf.position());
            System.out.println(buf.limit());
            System.out.println(buf.capacity());

     结果为

    // 7.虽让缓冲区的数据的数据被清空,但是依然存在,只是处于“被遗忘”状态
            System.out.println((char) buf.get());

     结果为

     

    mark:标记,表示记录当前position的位置,可以通过reset()恢复到mark的位置
    0<=mark<=position<=limit<=capacity

    String str = "abcde";
    
            ByteBuffer buf = ByteBuffer.allocate(1024);
    
            buf.put(str.getBytes());
    
            buf.flip();
    
            byte[] dst = new byte[buf.limit()];
            buf.get(dst, 0, 2);
            System.out.println(new String(dst, 0, 2));
    
            System.out.println(buf.position());
    
            // mark():标记
            buf.mark();
    
            buf.get(dst, 2, 2);
            System.out.println(new String(dst, 2, 2));
            System.out.println(buf.position());
    
            // reset:恢复到mark的位置
            buf.reset();
            System.out.println(buf.position());
            
            //判断缓冲区中的数量
            if(buf.hasRemaining()){
                System.out.println(buf.remaining());
            }

    4.文件通道(FileChannel)

     Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。

    FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

     

    打开FileChannel

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

    1 RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt""rw");
    2 FileChannel inChannel = aFile.getChannel();

    从FileChannel读取数据

    调用多个read()方法之一从FileChannel中读取数据。如:

    1 ByteBuffer buf = ByteBuffer.allocate(48);
    2 int bytesRead = inChannel.read(buf);

    首先,分配一个Buffer。从FileChannel中读取的数据将被读到Buffer中。

    然后,调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。

    向FileChannel写数据

    使用FileChannel.write()方法向FileChannel写数据,该方法的参数是一个Buffer。如:

    01 String newData = "New String to write to file..." + System.currentTimeMillis();
    02  
    03 ByteBuffer buf = ByteBuffer.allocate(48);
    04 buf.clear();
    05 buf.put(newData.getBytes());
    06  
    07 buf.flip();
    08  
    09 while(buf.hasRemaining()) {
    10     channel.write(buf);
    11 }

    注意FileChannel.write()是在while循环中调用的。因为无法保证write()方法一次能向FileChannel写入多少字节,因此需要重复调用write()方法,直到Buffer中已经没有尚未写入通道的字节。

    关闭FileChannel

    用完FileChannel后必须将其关闭。如:

    1 channel.close();

    FileChannel的position方法

    有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。

    也可以通过调用position(long pos)方法设置FileChannel的当前位置。

    这里有两个例子:

    1 long pos = channel.position();
    2 channel.position(pos +123);

    如果将位置设置在文件结束符之后,然后试图从文件通道中读取数据,读方法将返回-1 —— 文件结束标志。

    如果将位置设置在文件结束符之后,然后向通道中写数据,文件将撑大到当前位置并写入数据。这可能导致“文件空洞”,磁盘上物理文件中写入的数据间有空隙。

    FileChannel的size方法

    FileChannel实例的size()方法将返回该实例所关联文件的大小。如:

    1 long fileSize = channel.size();

    FileChannel的truncate方法

    可以使用FileChannel.truncate()方法截取一个文件。截取文件时,文件将中指定长度后面的部分将被删除。如:

    1 channel.truncate(1024);

    这个例子截取文件的前1024个字节。

    FileChannel的force方法

    FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。

    force()方法有一个boolean类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上。

    下面的例子同时将文件数据和元数据强制写到磁盘上:

     
    1 channel.force(true);

    5.NIO的非阻塞式网络通信

      1.选择器

      2.SocketChannel、ServerSocketChannel、DatagramChannel

    6.通道(Pipe)

    7.Java NIO(Path、Paths与Files)

     
  • 相关阅读:
    nginx能访问html静态文件但无法访问php文件
    LeetCode "498. Diagonal Traverse"
    LeetCode "Teemo Attacking"
    LeetCode "501. Find Mode in Binary Search Tree"
    LeetCode "483. Smallest Good Base" !!
    LeetCode "467. Unique Substrings in Wraparound String" !!
    LeetCode "437. Path Sum III"
    LeetCode "454. 4Sum II"
    LeetCode "445. Add Two Numbers II"
    LeetCode "486. Predict the Winner" !!
  • 原文地址:https://www.cnblogs.com/Chenghao-He/p/7705718.html
Copyright © 2011-2022 走看看