• IO编程之NIO


    从jdk1.4开始,java提供了一系列改进的输入/输出处理的新功能,这些功能被统称为新IO(New IO,简称NIO),这些类都被放在java.nio包以及子包中,并且对原java.io包中的很多类都以NIO为基础进行了改写,新增了满足NIO的功能。

    一、Buffer

    与Buffer各种相关的类主要在java.nio包中

    从内部结构上看Buffer就像一个数组,它可以保存多个相同类型相同的数据。

    Buffer是一个抽象类,最常用的子类是ByteBuffer,可以在底层字节数组上进行get/set操作。对应其他基本数据类型(boolean除外)都有相应的Buffer类:CharBuffer,ShortBuffer,IntBuffer...等.

    Buffer中有三个重要概念:

        1)容量(capacity):缓冲区的容量(capacity),标识Buffer的最大数据容量,不可为负值,创建后不能改变

        2)界限(limit):第一个不应该被读出或者写入的缓冲区位置索引,也就是说位于limit之后的数据既不可以被读,也不可以被写

        3)位置(position):用于指明下一个可以被读出或者写入的缓冲区位置索引

    @Test
        public void bufferTest() {      
            //创建一个CharBuffer
            CharBuffer cbuff = CharBuffer.allocate(8);
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
            //向cbuff中插入字符
            cbuff.put('a');
            cbuff.put('b');
            cbuff.put('c');
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
            //调用flip方法:将limit设置为position所在的位置,并将position设置为0,即为输出数据做好准备
            cbuff.flip();
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
            //取出cbuff中的元素
            System.out.println(cbuff.get());
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
            //调用clear方法:clear不是清空数据,她将position设置为0,将limit设置为capactity,即为存入数据做好准备
            cbuff.clear();
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
            //绝对取数
            System.out.println(cbuff.get(2));
            //绝对取数后相应的参数,绝对取数后相应的参数是不会变化的。
            System.out.println("cbuff的容量:"+cbuff.capacity());
            System.out.println("cbuff的界限:"+cbuff.limit());
            System.out.println("cbuff的位置:"+cbuff.position());
             
        }
         
        结果:       
                 cbuff的容量:8
                 cbuff的界限:8
                 cbuff的位置:0
                 cbuff的容量:8
                 cbuff的界限:8
                 cbuff的位置:3
                 cbuff的容量:8
                 cbuff的界限:3
                 cbuff的位置:0
                 a
                 cbuff的容量:8
                 cbuff的界限:3
                 cbuff的位置:1
                 cbuff的容量:8
                 cbuff的界限:8
                 cbuff的位置:0
                 c
                 cbuff的容量:8
                 cbuff的界限:8
                 cbuff的位置:0

    二、Channel

        Channel类似于传统的流对象,但与传统的流对象有两个主要区别:

        1)Channel可以直接将指定文件的部分或者全部直接映射成Buffer

        2)程序不能直接访问Channel中的数据,包括读取写入都不行,Channel只能与Buffer进行交互

    Channel接口的实现类有DatagramChannel、FileChannel、ServerSocketChannel、SocketChannel....等。主要是按功能来分的,DatagramChannel用于支持UDP网络通信的Channel,ServerSocketChannel、SocketChannel是用于支持TCP网络通信的Channel 等依次类推。

    /**
         * Channel测试
         * 将FileChannel的全部数据一次映射成ByteBuffer的效果
         */
        @Test
        public void fileChannelTest() {
            File f = new File("G://test//eda_src.sql");
            try (// 获取FileChannel
                FileChannel inChannel = new FileInputStream(f).getChannel();
                FileChannel outChannel = new FileOutputStream("G://test//eda_src_bak.sql").getChannel()) {
                //MappedByteBuffer是ByteBuffer的子类,它表示Channel将磁盘文件的部分内容或全部内容映射到内存后得到的结果
                //通常MappedByteBuffer是由Channel的map方法返回。
                MappedByteBuffer mbb = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
                //创建UTF-8创建解码器
                Charset charset = Charset.forName("UTF-8");
                //将buffer的数据全部输出
                outChannel.write(mbb);
                //将mbb恢复
                mbb.clear();
                //创建解码器
                CharBuffer cbuff = charset.decode(mbb);
                System.out.println(cbuff);
                 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
         
        /**
         * Channel测试
         * 如果Channel对应的文件过大,一次性映射到内存中引起性能下降,可以采用“竹筒多次重复取水”的方式
         * 实现文件复制
         */
        @Test
        public void fileChannelTest1() {
            File f = new File("G://test//eda_src.sql");
            try (// 获取FileChannel
                FileChannel inChannel = new FileInputStream(f).getChannel();
                FileChannel outChannel = new FileOutputStream("G://test//eda_src_bak1.sql").getChannel()) {
                //定义一个ByteBuffer对象,用于重复取水
                ByteBuffer bbuff = ByteBuffer.allocate(1024);
                 
                while(inChannel.read(bbuff) != -1) {
                    //准备读取数据
                    bbuff.flip();
                    outChannel.write(bbuff);
                    //准备写入数据
                    bbuff.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    三、字符集和Charset

    在计算机里所有的文件,数据等在底层都是二进制文件,即全部是字节码。对于文本文件,之所以看到一个个字符,这是因为系统将底层的二进制序列转换成字符的缘故。在这个过程中涉及到两个概念:编码(Encode)和解码(Decode)

    通常而言:

        Encode:把明文的字符序列转换成计算机所理解的二进制序列称为编码

        Decode:把二进制序列转换成普通人能看懂的明文字符串称为解码

    /**
         * 编码,解码
         * @throws Exception
         */
        @Test
        public void CharsetTest() throws Exception {
            Charset charset = Charset.forName("UTF-8");
            CharBuffer cbuff = CharBuffer.allocate(10);
            cbuff.put('孙');
            cbuff.put('悟');
            cbuff.put('空');
            cbuff.flip();
            ByteBuffer bbuff = charset.newEncoder().encode(cbuff);
            cbuff.clear();
            //编码
            System.out.println(bbuff.get(5));
            bbuff.flip();
            //解码
            System.out.println(charset.newDecoder().decode(bbuff));
        }

    四、NIO.2

    JAVA7对原有的NIO进行了重大改进,改进主要包括如下两方面的内容(java7把这种改进称为NIO.2)

        1)提供了全面的文件IO和文件系统访问支持(java7新增了java.nio.file包及各个子包)

        2)基于异步Channel的IO(java7在java.nio.channels新增了多个以Asynchronous开头的Channel接口和类)

    JAVA传统File类功能比较有限,NIO.2中引入了Path接口和Files、Paths两个工具类来弥补这种不足。

    /**
         * Paths测试
         * @throws Exception
         */
        @Test
        public void pathTest() throws Exception {
            //以当前路径来获取Path对象
            Path path = Paths.get(".");
            //path路径
            System.out.println(path);
            //绝对路径
            System.out.println(path.toAbsolutePath());
            //真实路径
            System.out.println(path.toRealPath());
            //获取路径名数量
            System.out.println(path.getNameCount());
            //获取绝对路径名数量
            System.out.println(path.toAbsolutePath().getNameCount());
            //获取真实路径名数量
            System.out.println(path.toRealPath().getNameCount());
        }
         
        /**
         * Files测试
         * @throws Exception
         */
        @Test
        public void filesTest() throws Exception {
     
            // 复制文件
                Files.copy(Paths.get("G://test//eda_src_bak1.sql"),
                        new FileOutputStream("G://test//eda_src_bak2.sql"));
            //判断文件是否为影藏文件
            System.out.println(Files.isHidden(Paths.get("G://test//eda_src_bak2.sql")));
            //一次性读取文件所有行
            List<String> lines = Files.readAllLines(Paths.get("G://test//eda_src_bak2.sql"));
            System.out.println(lines);
            //获取文件大小
            System.out.println(Files.size(Paths.get("G://test//eda_src_bak2.sql")));
            //直接将多个字符串内容写入到指定文件中
            List<String> l = new ArrayList<>();
            l.add("飞流直下三千尺");
            l.add("佛说因果有缘");
            Files.write(Paths.get("G://test//eda_src_bak3.sql"), l, Charset.forName("UTF-8"));
            //判断C盘总空间,可用空间
            FileStore cStore = Files.getFileStore(Paths.get("C:"));
            System.out.println("C盘总空间"+cStore.getTotalSpace());
            System.out.println("C可用空间"+cStore.getUsableSpace());
        }
         
        /**
         * 使用FileVistor遍历目录
         * FileVisitor接口代表一个文件访问器,定义了四个方法
         *        FileVisitResult visitFile(T file, BasicFileAttributes attrs) 访问文件时触发该方法
         *        FileVisitResult visitFileFailed(T file, IOException exc)    访问文件失败时触发该方法
         *        FileVisitResult postVisitDirectory(T dir, IOException exc)  访问子目录之前触发该方法
         *        FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) 访问子目录之后触发该方法
         * 四个方法会返回FileVisitResult对象,这是一个枚举类
         *        CONTINUE:继续访问
         *        SKIP_SIBLINGS:继续访问,但不访问该文件或目录的兄弟文件或目录
         *        SKIP_SUBTREE:继续访问,但不访问该文件或目录的子目录树
         *        TERMINATE:终止访问
         *       
         * @throws Exception 
         */
        @Test
        public void FileVistorTest() throws Exception {   
            //遍历G:	est所有文件及子目录
            Files.walkFileTree(Paths.get("G://test"), new SimpleFileVisitor<Path>() {
     
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println(file.toRealPath());
                    return FileVisitResult.CONTINUE;
                     
                }  
                 
            });
  • 相关阅读:
    VANET
    OTCL,面向对象的脚本一
    NetFPGA-SUME下reference_nic测试
    Mininet-wifi安装和简单使用
    18寒假
    DistBlockNet:A Distributed Blockchains-Based Secure SDN Architecture for IOT Network
    SDVN
    Papers3
    高级软件工程实践总结
    Beta集合
  • 原文地址:https://www.cnblogs.com/jnba/p/10535729.html
Copyright © 2020-2023  润新知