多线程

JAVA NIO

2019-04-21  本文已影响0人  虫儿飞ZLEI

也是IO操作,比如读写文件什么的,只是与传统IO操作方式不一样。

image.png 传统IO

缓冲区像火车一样,在通道中来回传输数据

NIO

2. 使用

缓冲区存取数据的两个核心方法:

put(): 存入数据到缓冲区
get(): 获取缓冲区的数据

缓冲区中的四个核心属性

缓冲区都继承Buffer image.png
    @org.junit.Test
    public void test1(){
        //1.分配指定大小的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        System.out.println(buffer.position());
        System.out.println(buffer.limit());
        System.out.println(buffer.capacity());

        buffer.put("111".getBytes());
        System.out.println(buffer.position());
        System.out.println(buffer.limit());
        System.out.println(buffer.capacity());

        //切换到读取模式,后,positon和limit的值都会 变化
        buffer.flip();

        System.out.println(buffer.position());
        System.out.println(buffer.limit());
        System.out.println(buffer.capacity());

        buffer.get();
        System.out.println(buffer.position());
        System.out.println(buffer.limit());
        System.out.println(buffer.capacity());
    }
buf.rewind() :可重复读数据,相当于重置。就可以重新读取数据了

buf.clear(): 清空缓冲去,但是缓冲区的数据依然存在,只是把position和limit这些重置成最开始的状态,但是以前的数据还在的。

3 直接缓冲区和非直接缓冲区

    @org.junit.Test
    public void test2(){
        //分配直接缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
        //判断当前是否是直接缓冲区
        System.out.println(byteBuffer.isDirect());
    }

4 通道

通道的主要实现类

获取通道三种方式;

  1. 针对支持通道的类提供的getChannel方法
  1. 针对各个通道提供了静态方法Open(),jdk
    1.7
    FileChannel.open()
  1. Files工具类的newByteChannel
    Files.newByteChannel()

5. 复制文件示例

复制文件示例(非直接缓冲区)

    @org.junit.Test
    public void test3(){
        //获取流
        FileInputStream fis = null;
        FileOutputStream fos = null;

        //获取通道
        FileChannel inChannel  = null;
        FileChannel outChannel = null;

        try {
            fis = new FileInputStream("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.jpg");
            fos = new FileOutputStream("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\2.jpg");

            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

            //分配指定大小的缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            //将通道中的数据存入缓冲区中
            while(inChannel.read(buffer) != -1){
                //切换到读取缓冲区数据的模式
                buffer.flip();
                //将缓冲区的数据写到通道中
                outChannel.write(buffer);
                //清空缓冲区
                buffer.clear();
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (inChannel == null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outChannel == null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis == null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos == null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

使用直接缓冲区完成文件的复制(效率高)

    @org.junit.Test
    public void test4(){
        try {
            //StandardOpenOption.READ这里的读写要和下面的缓冲区的FileChannel.MapMode.READ_ONLY一致
            FileChannel inChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.txt"), StandardOpenOption.READ);
            //StandardOpenOption.CREATE_NEW,创建新文件,文件已存在的话就报错,
            //StandardOpenOption.CREATE,创建新文件,覆盖老文件
            FileChannel outChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\3.txt"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);

            //这里的FileChannel.MapMode.READ_ONLY要和上面的StandardOpenOption.READ一致
            MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
            MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

            byte[] dst = new byte[inMappedBuf.limit()];
            inMappedBuf.get(dst);
            outMappedBuf.put(dst);

            inChannel.close();
            outChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

复制文件(通道之间的数据传输(直接缓冲区))

    @org.junit.Test
    public void test5() throws IOException {
        //StandardOpenOption.READ这里的读写要和下面的缓冲区的FileChannel.MapMode.READ_ONLY一致
        FileChannel inChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.txt"), StandardOpenOption.READ);
        //StandardOpenOption.CREATE_NEW,创建新文件,文件已存在的话就报错,
        //StandardOpenOption.CREATE,创建新文件,覆盖老文件
        FileChannel outChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\5.txt"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);
        
        inChannel.transferTo(0,inChannel.size(),outChannel);
        //或者,效果和上一行一样
        outChannel.transferFrom(inChannel,0,inChannel.size());
        
        inChannel.close();
        outChannel.close();
    }

6. 分散与聚集

分散读取:

将通道数据分散到多个缓冲区中


聚集写入:

将多个缓冲区中的数据聚集到通道中


    @org.junit.Test
    public void test6() throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.txt", "rw");

        FileChannel channel1 = randomAccessFile.getChannel();

        ByteBuffer buffer1 = ByteBuffer.allocate(100);
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);

        ByteBuffer[] byteBuffers = {buffer1,buffer2};
        //分散读取,依次读取到buffer中
        channel1.read(byteBuffers);

        buffer1.flip();
        buffer2.flip();

        System.out.println(new String(buffer1.array(),0,buffer1.limit()));
        System.out.println("------------");
        System.out.println(new String(buffer2.array(),0,buffer2.limit()));

        RandomAccessFile randomAccessFile2 = new RandomAccessFile("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\6.txt", "rw");
        FileChannel channel2 = randomAccessFile2.getChannel();
        //聚集写入
        channel2.write(byteBuffers);
    }

7. 阻塞式NIO(网络IO TCP)

    @org.junit.Test
    public void client() throws IOException {
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        FileChannel fileChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.txt"), StandardOpenOption.READ);
        while (fileChannel.read(buffer) != -1){
            buffer.flip();
            socketChannel.write(buffer);
            buffer.clear();
        }

        socketChannel.close();
        fileChannel.close();
    }

    @org.junit.Test
    public void server() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        serverSocketChannel.bind(new InetSocketAddress(9898));

        SocketChannel socketChannel = serverSocketChannel.accept();

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        while (socketChannel.read(byteBuffer) != -1){
            System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
            System.out.println("----");
            byteBuffer.clear();
        }

        serverSocketChannel.close();
        socketChannel.close();
    }

8. 非阻塞式NIO(网络IO TCP)

image.png
    @org.junit.Test
    public void client() throws IOException {
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));

        //切换成非阻塞模式
        socketChannel.configureBlocking(false);

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        FileChannel fileChannel = FileChannel.open(Paths.get("D:\\WorkSpace\\WorkSpace\\Java_idea\\NIO\\nio\\src\\main\\resources\\1.txt"), StandardOpenOption.READ);
        while (fileChannel.read(buffer) != -1){
            buffer.flip();
            socketChannel.write(buffer);
            buffer.clear();
        }

        socketChannel.close();
        fileChannel.close();
    }

    @org.junit.Test
    public void server() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //切换成非阻塞模式
        serverSocketChannel.configureBlocking(false);

        serverSocketChannel.bind(new InetSocketAddress(9898));

        //获取选择器
        Selector selector = Selector.open();

        //将通道注册到选择器上,并且指定监听事件,可选多个
        serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

        //轮询获取选择器上已经准备就绪的事件
        while (selector.select()>0){
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                //获取准备就绪的事件
                SelectionKey key = iterator.next();
                System.out.println(key);

                if (key.isAcceptable()){
                    SocketChannel socketChannel = serverSocketChannel.accept();

                    //切换非阻塞模式
                    socketChannel.configureBlocking(false);
                    //注册
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }else if (key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    while (channel.read(byteBuffer) != -1){
                        System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
                        System.out.println("----");
                        byteBuffer.clear();
                    }
                    channel.close();
                }
                iterator.remove();
            }
        }
        serverSocketChannel.close();
    }

9 非阻塞式NIO(网络IO UDP)

    @org.junit.jupiter.api.Test
    public void client2() throws IOException {
        DatagramChannel datagramChannel = DatagramChannel.open();
        datagramChannel.configureBlocking(false);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            String str = scanner.next();
            buffer.put(str.getBytes());
            buffer.flip();
            datagramChannel.send(buffer,new InetSocketAddress("127.0.0.1",9898));
            buffer.clear();
        }
        datagramChannel.close();
    }

    @org.junit.Test
    public void server2() throws IOException {
        DatagramChannel datagramChannel = DatagramChannel.open();
        datagramChannel.configureBlocking(false);

        datagramChannel.bind(new InetSocketAddress(9898));

        Selector selector = Selector.open();

        datagramChannel.register(selector, SelectionKey.OP_READ);

        while (selector.select()>0){
            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
            while (keys.hasNext()){
                SelectionKey sk = keys.next();
                if (sk.isReadable()){
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    datagramChannel.receive(buffer);
                    buffer.flip();
                    System.out.println(new String(buffer.array(),0,buffer.limit()));
                    buffer.clear();
                }
            }
            keys.remove();
        }
    }
上一篇下一篇

猜你喜欢

热点阅读