java NIO的入门使用,学习记录,持续更新

一、NIO简单介绍

non-blocking io 非阻塞 IO,它的出现主要就是为了应对连接多传输量小的连接;因为传统IO(inputstream和outputstream)是线程阻塞,不能应对大量连接的使用场景;那么传统io是不是就没有用武之地了呢?答案肯定是;传统io适用于连接少并且传输量大的场景。

阻塞就是cpu一直被一个线程占用,即使没有了任务它也不能去做其他线程的任务,严重浪费资源;当然,如果阻塞的时候,cpu一直在为当前线程干活那么就不存在资源浪费的情况,那么这种场景下传统io就完全可以应对的。

nio主要分三大块:channel、byteBuffer、selector

channel的read方法将数据写到bytebuffer,然后通过bytebuffer的get方法将数据读到内存

二、nio简单使用

1.读取文件并打印内容

在resource下新建一个文件,然后编辑填入

123456789asd
public void nioDemo() {
        // 类加载器获取文件路径
        String path = null;
        try {
            path = NioDemo.class.getClassLoader().getResource("demo.txt").getPath();
            log.debug("文件地址:{}", path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try (FileChannel channel = new FileInputStream(path).getChannel()) {
            //分配buffer空间
            ByteBuffer byteBuffer = ByteBuffer.allocate(10);
            byte[] aByte = new byte[10];
            int count;
            while ((count = channel.read(byteBuffer))>0){//读数据时pos指针会从0处往后移动,当读不到数据时会返回-1
                log.debug("读取到的字节数 {}", count);
                //切换读模式(就是改变pos指针的位置到0处开始读数据,并且limit记录了pos的位置,避免读到空)
                byteBuffer.flip();
                while (byteBuffer.hasRemaining()){//判断当前指针pos是不是小于limit指针(limit指针标记最大可读数量)
                    byte b = byteBuffer.get();//每次读一个字节
                    log.debug(String.valueOf((char)b));
                }
                //切换写模式(读完数据后,指针会到达limit处,所以要再次切换pos位置到0处)或者compact()
                byteBuffer.clear();
            }

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

2.byteBuffer一些用法
flip和clear的区别

public void byteBufferUsage1(){
        // 这里分配10个字节空间
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 通过put方法存值,使用putChar一次暂用2个字节
        byteBuffer.putChar('a');
        byteBuffer.putChar('b');
        byteBuffer.putChar('c');
        // 切换读模式
        byteBuffer.flip();
        // 如果这边使用byteBuffer.clear()会出现下面结果;
        // 解释:clear类似与重置byteBuffer里面的指针的位置(并不会清空数据),pos:0,limit:10,cap:10,这样再读取的时候,就会把剩余的4个字节也读了,
        // 而使用byteBuffer.flip(),只会把pos指针的位置变成0,limit依旧在6的位置
        //15:11:23 [DEBUG] [main] c.w.nio.NioDemo - a
        //15:11:23 [DEBUG] [main] c.w.nio.NioDemo - b
        //15:11:23 [DEBUG] [main] c.w.nio.NioDemo - c
        //15:11:23 [DEBUG] [main] c.w.nio.NioDemo -
        //15:11:23 [DEBUG] [main] c.w.nio.NioDemo -

        //正确结果:
        //15:23:31 [DEBUG] [main] c.w.nio.NioDemo - a
        //15:23:31 [DEBUG] [main] c.w.nio.NioDemo - b
        //15:23:31 [DEBUG] [main] c.w.nio.NioDemo - c
        while (byteBuffer.hasRemaining()){
            char aChar = byteBuffer.getChar();
            log.debug(String.valueOf(aChar));
        }
    }
使用compact()来切换写模式,会把未读的数据提出来放到数组前面,然后再从他们后面开始写
public void byteBufferUsage2(){
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 通过put方法存值
        byteBuffer.putChar('a');
        byteBuffer.putChar('b');
        byteBuffer.putChar('c');
        // 切换读模式
        byteBuffer.flip();
        // 使用compact()来切换写模式,会把未读的数据提出来放到数组前面,然后再从他们后面开始写
        // 先读一个a再使用compact(),然后再写一个a,然后再读出所有的,那么打印结果就变成:b c a
        // 结果与预期一样:
        //15:27:42 [DEBUG] [main] c.w.nio.NioDemo - 读出一个a:a
        //15:27:42 [DEBUG] [main] c.w.nio.NioDemo - b
        //15:27:42 [DEBUG] [main] c.w.nio.NioDemo - c
        //15:27:42 [DEBUG] [main] c.w.nio.NioDemo - a
        char c = byteBuffer.getChar();
        log.debug("读出一个a:{}", c);
        byteBuffer.compact();
        byteBuffer.putChar('a');
        byteBuffer.flip();
        while (byteBuffer.hasRemaining()){
            char aChar = byteBuffer.getChar();
            log.debug(String.valueOf(aChar));
        }
    }
get(int i)方法读取和get()的区别
public void byteBufferUsage3(){
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 通过put方法存值
        byteBuffer.putChar('a');
        byteBuffer.putChar('b');
        byteBuffer.putChar('c');
        // 切换读模式
        byteBuffer.flip();
        // get(int i)方法不会让pos指针往下走,这样可以重复读那一个字节的数据
        // 执行多次读取a的操作
        //15:41:34 [DEBUG] [main] c.w.nio.NioDemo - 读出一个a:a
        //15:41:34 [DEBUG] [main] c.w.nio.NioDemo - 读出一个a:a
        //15:41:34 [DEBUG] [main] c.w.nio.NioDemo - 读出一个a:a
        byte a = byteBuffer.get(1);
        log.debug("读出一个a:{}", (char)a);
        byte b = byteBuffer.get(1);
        log.debug("读出一个a:{}", (char)b);
        byte c = byteBuffer.get(1);
        log.debug("读出一个a:{}", (char)c);
    }
byteBuffer.rewind()方法会让pos指针重置到0,那就可以多次读取;和flip()很像,但它不会将limit位置变成pos
public void byteBufferUsage4(){
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 通过put方法存值
        byteBuffer.putChar('a');
        byteBuffer.putChar('b');
        byteBuffer.putChar('c');
        // 切换读模式
        byteBuffer.flip();
        // byteBuffer.rewind()方法会让pos指针重置到0,那就可以多次读取;和flip()很像,但它不会将limit位置变成pos
        while (byteBuffer.hasRemaining()){
            char aChar = byteBuffer.getChar();
            log.debug(String.valueOf(aChar));
        }
        byteBuffer.rewind();
        log.debug("再来一次读取》》》");
        while (byteBuffer.hasRemaining()){
            char aChar = byteBuffer.getChar();
            log.debug(String.valueOf(aChar));
        }
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - a
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - b
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - c
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - 再来一次读取》》》
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - a
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - b
        //15:50:43 [DEBUG] [main] c.w.nio.NioDemo - c
    }
byteBuffer.mark()可以标记位置,再通过byteBuffer.reset(),会将pos指向mark标记的位置来实现标记重复读的操作
注意:rewind 和 flip 都会清除 mark 位置
public void byteBufferUsage5(){
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        // 通过put方法存值
        byteBuffer.putChar('a');
        byteBuffer.putChar('b');
        byteBuffer.putChar('c');
        // 切换读模式
        byteBuffer.flip();
        // byteBuffer.mark()可以标记位置,再通过byteBuffer.reset(),会将pos指向mark标记的位置来实现标记重复读的操作
        // 注意:rewind 和 flip 都会清除 mark 位置

        char c = byteBuffer.getChar();
        log.debug("读了一个:{}", c);
        byteBuffer.mark();
        log.debug("加了一个标记mark,继续往下读>>>");
        while (byteBuffer.hasRemaining()){
            log.debug(String.valueOf(byteBuffer.getChar()));
        }
        log.debug("从标记位置再读一次>>>");
        byteBuffer.reset();
        while (byteBuffer.hasRemaining()){
            log.debug(String.valueOf(byteBuffer.getChar()));
        }
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - 读了一个:a
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - 加了一个标记mark,继续往下读>>>
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - b
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - c
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - 从标记位置再读一次>>>
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - b
        //16:02:07 [DEBUG] [main] c.w.nio.NioDemo - c
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值