zoukankan      html  css  js  c++  java
  • java核心学习(十八) javaNIO框架---“块”模型的IO

    一、java新IO概述

      javaIO中的输入流和输出流都是通过字节的移动来处理的,面向流的输入输出系统一次只能处理一个字节,因此效率不高,而且传统的输入输出流是阻塞试的,也就是说当无法读到数据时,当前线程会被阻塞直到读取到有效数据才会继续运行。

      java1.4之后提供了一系列改进的输入输出类与方法,并且以NIO为基础改写了java.io包中的类,新增了满足NIO的功能。

      NIO采用内存映射文件的方式,java.nio中主要的包有:

        java.nio ,主要包含于Buffer相关的类;

        java.nio.charset,主要包含字符集相关的类;

        java.nio.channels,主要包含Channel和Selector相关的类;

        java.nio.channels.spi,主要包含与Channel相关的服务提供者编程接口;

        java.nio.charset.spi,包含与字符集相关的服务提供者编程接口。

    二、Buffer抽象类

      其子类有ByteBuffer(最常用)、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer,这些类没有构造器,获取buffer对象使用如下静态方法:static XxxBuffer allocate(int capacity)。

      Buffer的几个位置属性:

      

      相应的两个方法:clear(),let limit = capacity and position = 0,这相当于是为再次将数据写入Buffer做好准备,

              flip(),let limit = position and position = 0 ,这相当于是为从Buffer中取出数据做好准备。

    package NIOTest;
    
    import java.nio.CharBuffer;
    
    public class BufferTest {
        public static void main(String[] args)
        {
            CharBuffer buffer = CharBuffer.allocate(8);
            System.out.println("capacity:" +buffer.capacity());
            System.out.println("limit:" +buffer.limit());
            System.out.println("position" + buffer.position());
    
            buffer.put('a');
            buffer.put('b');
            buffer.put('c');
            System.out.println("加入三个元素后,position = " + buffer.position());
            buffer.flip();
            System.out.println("执行flip()后,limit = " + buffer.limit());
            System.out.println("position = " + buffer.position());
            //去除第一个元素
            System.out.println("第一个元素(position=0):" + buffer.get());
            System.out.println("取出第一个元素后,position = " + buffer.position());
            //调用clear方法
            buffer.clear();
            System.out.println("执行clear()后,limit = " + buffer.limit());
            System.out.println("执行clear()后,position = " + buffer.position());
            System.out.println("执行clear()后,buffer内容并没有被清除:" + "第三个元素为:"+ buffer.get(2));
            System.out.println("执行绝对读取后,position = " + buffer.position());
        }
    }

      上面代码尝试了一下Buffer的使用,输出为下

    capacity:8
    limit:8
    position0
    加入三个元素后,position = 3
    执行flip()后,limit = 3
    position = 0
    第一个元素(position=0):a
    取出第一个元素后,position = 1
    执行clear()后,limit = 8
    执行clear()后,position = 0
    执行clear()后,buffer内容并没有被清除:第三个元素为:c
    执行绝对读取后,position = 0

      上面程序使用的buffer是heapbuffer,每个heapbuffer在新建时都会创建一个对应的directbuffer,直接buffer的读取效率高但是创建成本也高,具体buffer1的工作方式不在这里深究= =,因为深究了没有实际应用也会忘记。。

    三、 Channel接口

      Channel用于与Buffer交互,实现数据的IO。

      java为Channel接口提供了DatagramChannel(支持UDP网络通信)、FileChannel(文件读写)、Pipe.SinkChannel和Pipe.SourceChannel(支持线程间通信的管道)、SelectableChannel(可选择阻塞与非阻塞的channel)、ServerSocketChannel和SocketChannel(支持TCP网络通信)等等。

      Channel通过传统的流节点来返回对应的Channel,常用的方法有map()、read()、write(),下面来试一试

      

    package NIOTest;
    
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.CharBuffer;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    
    public class FileChannelTest {
        public static void main(String[] args) {
            File f = new File("./src/main/java/NIOTest/FileChannelTest.java");
            try (
                    FileChannel inChannnel = new FileInputStream(f).getChannel();
                    FileChannel outChannel = new FileOutputStream("a.txt").getChannel();
    
            ) {
                MappedByteBuffer buffer = inChannnel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
                Charset charset = Charset.forName("GBK");
                outChannel.write(buffer);
                buffer.clear();
                CharsetDecoder decoder = charset.newDecoder();
                CharBuffer charBuffer = decoder.decode(buffer);
                System.out.println(charBuffer);
    
    
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

      下面代码每次运行都会讲a.txt文件的内容复制一份并将全部内容追加到该文件的后面

    package NIOTest;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class RandomFileChannelTest {
        public static  void mian (String[] args){
            File f= new File("a.txt");
            try(
                    RandomAccessFile raf = new RandomAccessFile(f,"rw");
                    FileChannel randomChannel = raf.getChannel();
                    ){
                ByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY,0,f.length());
           //这里移动的是channel的position,可以在任意位置将数据写入channel。 randomChannel.position(f.length()); randomChannel.write(buffer); }
    catch (IOException ioe){ ioe.printStackTrace(); } } }

    四、Charset类

      字符集类主要用于文本格式数据编码与解码,具体用法在 三 中的第一个例子有所展示。

  • 相关阅读:
    VS2015编译OpenSSL1.0.2源码
    VS2015编译CURL7.54.0源码
    Mac OS Yosemite 文件批量重命名
    https 原理
    把本地仓库导入到Github
    jquery cdn加速注意事项
    关于CSS 里的_width是什么意思???
    HTML的footer置于页面最底部的方法
    html-include
    GitHub Permission to <<repository>> denied to <<username>>
  • 原文地址:https://www.cnblogs.com/Theshy/p/7535745.html
Copyright © 2011-2022 走看看