nio

こ雲淡風輕ζ 提交于 2019-12-02 20:55:27
概述
    nio是另一种处理io的方式
    非阻塞io,基于缓冲区进行操作,一个线程可处理多个io请求
    入门参考:
        http://www.iteye.com/magazines/132-Java-NIO
        http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html



和io进对比
    区别
        面向流和面向缓冲区
            io是面向流的
            nio面向缓冲区
        阻塞与非阻塞
            io是阻塞的
            nio是非阻塞的(read方法立即返回)
        线程利用
            io是一个线程管理一个io请求
            nio是一个线程可以管理多个io请求(通过selectors监听并选择准备就绪的通道)



通道和缓冲区(Channel和Buffer)
    概述
        NIO是基于通道(Channel)和缓冲区(Buffer)进行操作的
        数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中
    通道
        通道就像io中的流一样,可以从流对象获得
        区别在于通道是双向的,流只能在一个方向上移动(一个输入流,一个输出流),但一个通道可同时应用于读写请求
    缓冲区
        本质上是一个数组,是内存中的一小块区域,通常是一个字节数组
        读取数据时,数据先读到缓冲区中,再读到通道中
        写入数据时,数据先写到缓冲区中,再写到通道中
    常用通道
        FileChannel             文件通道
        DatagramChannel         UDP通道
        SocketChannel           TCP通道
        ServerSocketChannel     可监听新进来的TCP连接
    常用缓冲区
        ByteBuffer
        CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer
    简单示例(复制文件)
        //获得输入通道
        FileInputStream in = new FileInputStream(IOUtils.getHomeDirectoryPath()+"/test.txt");
        FileChannel readChannel = in.getChannel();
        //获得输出通道
        FileOutputStream out = new FileOutputStream(IOUtils.getHomeDirectoryPath()+"/test2.txt");
        FileChannel writeChannel = out.getChannel();
        //创建缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //读取和写入文件
        for(;;){
            int len = readChannel.read(buffer); //读取文件
            if(len!=-1){
                buffer.flip();                  //转换到写模式
                writeChannel.write(buffer);     //写入文件
                buffer.clear();                 //清空缓存区
            }else{
                break;
            }
        }
        //关闭流
        in.close();
        out.close();



缓冲区
    底层原理
        底层是数组, 并且存在三个变量
            position: 
                读取时,下一个放入字节的位置(初始为0)
                写入时,下一个读取字节的位置(初始为0)
            limit: 
                读取时,可读取的最大容量(即数组的长度)
                写入时,可写入的最大容量(即实际占用的数据长度)
            capacity: 数组的最大容量(即数组的长度)
        flip方法
            将limit设置为position
            将position设置为0
        clear方法
            将limit设置为capacity
            将position设置为0
    操作方法(以ByteBuffer为例)
        创建
            ByteBuffer.allocate(int size);
        读取数据
            byte get() 
                读取下一个字节
            byte get(int index)
                读取指定位置的字节
            ByteBuffer get(byte[] dst) 
                读取字节到指定数组中 
            ByteBuffer get(byte[] dst, int offset, int length) 
                读取指定位置的字节到指定数组中 
        写入数据
            ByteBuffer put( byte b );
                写入一个字节
            ByteBuffer put( byte src[] );
                写入一个字节数组
            ByteBuffer put( byte src[], int offset, int length );
                写入一个字节数组的指定位置到缓冲区
            ByteBuffer put( ByteBuffer src );
                写入一个ByteBuffer的内容到缓冲区
            ByteBuffer put( int index, byte b );
                写入一个字节数组到缓冲区的指定位置
        其它
            byte[] array() 
                返回实现此缓冲区的 byte 数组 
            int capacity() 
                返回此缓冲区的容量。 
            Buffer clear() 
                清除此缓冲区。 
            Buffer flip() 
                反转此缓冲区。 
            Buffer mark() 
                在此缓冲区的位置设置标记。 
            Buffer reset() 
                将此缓冲区的位置重置为以前标记的位置。 



通道
    FileChannel
        用来操作文件的通道
        获得实例
            FileInputStream.getChannel()
            FileOutputStream.getChannel()
            RandomAccessFile.getChannel()       //RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
        常用方法
            int read(ByteBuffer dst) 
                将字节序列从此通道读入给定的缓冲区。 
            long read(ByteBuffer[] dsts) 
                将字节序列从此通道读入给定的缓冲区。 
            int write(ByteBuffer src) 
                将字节序列从给定的缓冲区写入此通道。 
            long write(ByteBuffer[] srcs) 
                将字节序列从给定的缓冲区写入此通道。 
            long transferFrom(ReadableByteChannel src, long position, long count) 
                将字节从给定的可读取字节通道传输到此通道的文件中。 (不通过缓冲区)
            long transferTo(long position, long count, WritableByteChannel target) 
                将字节从此通道的文件传输到给定的可写入字节通道。 (不通过缓冲区)
            void close() 
                关闭此通道。 
    SocketChannel
    ServerSocketChannel
    DatagramChannel
        



选择器(selector)
    概述
        能够监听多个通道的事件(如是否已经可读)
        方便使用单线程处理多个通道
    创建
        Selector.open()
    注册通道
        只能注册处于非阻塞模式下的通道(FileChannel不可以)
        hannel.configureBlocking(false);  
        SelectionKey key = channel.register(selector, Selectionkey.OP_READ);  
    可监听的事件
        SelectionKey.OP_CONNECT     连接
        SelectionKey.OP_ACCEPT      接受
        SelectionKey.OP_READ        读取
        SelectionKey.OP_WRITE       写入





















易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!