zoukankan      html  css  js  c++  java
  • Java关于NIO类的详解

    一、IO与NIO的区别:

      前提我们先说一说java IO: 

      Java中使用IO(输入输出)来读取和写入,读写设备上的数据、硬盘文件、内存、键盘......,根据数据的走向可分为输入流输出流,这个走向是以内存为基准的,即往内存中读数据是输入流,从内存中往外写是输出流

      根据处理的数据类型可分为字节流和字符流:

      1.字节流可以处理所有数据类型的数据,在java中以Stream结尾

      2.字符流处理文本数据,在java中以ReaderWriter结尾

    我们来看个IO流的详解图:

      1.NIO的起源:

        java.NIO是jdk1.4是提出,jdk1.7进行二次改进的java新型IO类,其最大的特点就是它的非阻塞性。

      2.IO与NIO结构差异:

        普通的IO是面向流(Stream Oriented),而NIO则是面向缓冲区(Buffer Oriented)。IO流是单向的,直接面向字节流,通过InputStream、OutputStream来完成数据的输入输出。而NIO是双向的,通过建立通道Channel),然后将数据装在缓冲区Buffer)在通道上进行传输。针对不同类型的数据有不同的Buffer,根据数据类型不同(boolean 除外),提供了相应类型的缓冲区: ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、 FloatBuffer、DoubleBuffer

    二、NIO的Buffer的数据存取:

      1.创建Buffer实例:

    ByteBuffer buf = ByteBuffer.allocate(1024); //1024为capacity,通过allocate()方法可以获取一个缓冲区

      2.Buffer类属性的解析:

        Buffer类中有三个属性必须理解:capacity容量)、limit(访问范围)、position位置,表示缓冲区中正在操作数据的位置)。通过get(),put()方法进行数据的存取。

        通过flip()方法切换成读模式,clear()方法清空缓冲区。但是缓冲区中的数据依然存在,但是处于“被遗忘”状态,rewind()可重复读。

      3.Buffer的分类:

        Buffer分为直接缓冲区非直接缓冲区。非直接缓冲区 通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中。直接缓冲区 通过allocateDirect()方法,将缓冲区建立在物理内存中。这样做可以提高IO效率,节省了copy的过程,直接缓冲区是物理内存映射文件,但是写入过程不受控制,读过程受GC影响!

    三、通道的原理与获取:

      1.通道的原理:

        传统的javaIO是通过DMA的方式存取,这种方式需要CPU的权限。而通道Channel)自带处理器,不需要去访问CPU,所以在进行大量IO时效率更高一些。通道用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。

      2.通道的获取:

        通道的主要实现类 java.nio.channels.Channel 接口:FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel。

        获取通道的方法:

          1)各IO有自己的获取方法、

          2)jdk1.7的NIO2,针对各个通道提供了静态方法open();

          3)jdk1.7的NIO2的Files工具类的newByteChannel();

    四、通道的数据传输:

      1.分散(Scatter)与聚集(Gather):  

        1)分散读取Scattering Reads),将Channel中读取的数据分散到Buffer
        2)聚集写入Gathering Writes),将多个Buffer中的数据聚集到Channel中

      2.实例代码:

            RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");       
            //1. 获取通道
            FileChannel channel = raf1.getChannel();     
            //2. 分配指定大小的缓冲区
            ByteBuffer buf1 = ByteBuffer.allocate(250);
            ByteBuffer buf2 = ByteBuffer.allocate(500);        
            //3. 分散读取
            ByteBuffer[] bufs = {buf1, buf2};
            channel1.read(bufs);      
            for (ByteBuffer byteBuffer : bufs) {
                byteBuffer.flip();
            }
            System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
            System.out.println("-----------------");
            System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));       
            //4. 聚集写入
            RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");
            FileChannel channel2 = raf2.getChannel();   
            channel2.write(bufs);

    五、字符集 Charset:

      编码:字符串->字节数组。解码:字节数组->字符串

      1.查看Charset里都有哪些编码:

            Map<String, Charset> map = Charset.availableCharsets();
            map.forEach((k,v)->{
                System.out.println(k);//常见的UTF-8等等..
            });

      2.缓冲区编解码:

            Charset c = Charset.forName("UTF-8");
            CharsetEncoder e = cs1.newEncoder();  //获取编码器
            CharsetDecoder d = cs1.newDecoder();  //获取解码器    
            CharBuffer buf = CharBuffer.allocate(1024);
            buf.put("二狗子到此一游");
            buf.flip();
            ByteBuffer bBuf = e.encode(buf );//编码
            bBuf.flip();                     //解码
            CharBuffer buf2= d.decode(bBuf);
            System.out.println(buf2.toString());    

    六、阻塞与非阻塞:

      阻塞与非阻塞式的,相较于网络通信:
        1)阻塞:C端发送S端读写请求,S端考虑,阻塞,服务端不会做其他事情,解决方式多线程
        2)非阻塞:Selector(选择器),通道会注册到选择器上,Selector监控IO状况,只有C端准备就绪

  • 相关阅读:
    clion中配置glfw和glew
    oracle xe在centos下的安装(更)
    git服务搭建以及本地连接
    IDEA导入Maven多项目(Mac下)
    关于反射的学习理解
    MySQL安装及后续配置
    idea配置servlet记录,tmocat当服务器,学习
    mapper映射文件配置之select、resultMap、resultType
    mysql多表查询
    看看阿里员工分享的java知识
  • 原文地址:https://www.cnblogs.com/zpdMulti/p/596957458_qq7.html
Copyright © 2011-2022 走看看