NIO流的学习

Posted auge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NIO流的学习相关的知识,希望对你有一定的参考价值。

NIO的使用

一)、什么叫NIO?

定义:是一套新的Java I/O标准, 在java1.4中被纳入JDK中。

二)、NIO的实现方法

NIO是基于块的, 以块为基本单位处理数据。

标准的I/O是基于流实现的,以字节为单位处理数据。

三)、NIO的特性

1).为所有的原始类型特供Buffer支持

    ByteBuffer

    CharBuffer

    DoubleBuffer

    FloatBuffer

    IntBuffer

    LongBuffer

    ShortBuffer

2).字符集编码解码解决方案,使用java.nio.Charset

3) .增加通道(Channel)对象,做为新的原始的I/O抽象

4).支持锁和内存映射文件的文件访问接口

5).提供了基于Selector的异步网络I/O

四)、NIO的两个重要组件

Buffer: 缓冲, 是一块连续的内存块,是NIO中读写数据的中转地。

Channel: 通道, 表示缓冲数据的源头或目的地。

Buffer和Channel的关系:

Channel作为数据的源头:从Channel中写数据到Buffer

Channel    --------->     Buffer

Channel作为数据的目的地:从Buffer中写出数据到Channel

     Channel   <---------      Buffer

五)、NIO的Buffer类族和Channel

Buffer: 是一个抽象类,JDK为每一种Java原生类型都创建了一个Buffer.

注: 除了ByteBuffer外,其它每一种Buffer都具有完全一样的操作。

原因:ByteBuffer多用于绝大多数数标准I/O操作的接口。

Channel: 是一个双向通道,既可读也可写。

注:应用程序中不能直接对Channel进行读写操作,在读取Channel时,需要先将数据读入到相对应的Buffer中,然后在Buffer中进行读取。

使用Buffer读取文件:

public class Nio_Buffer_Channel {
    public static void main(String[] args) throws IOException {
        //获取一个输入流对象
        FileInputStream fin = new FileInputStream("d:/a.txt");
        //获取输入流对象的通道,作为数据的源头
        FileChannel fileChannel = fin.getChannel();
        //创建一个Buffer对象
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //从通道中读取数据到Buffer中
        fileChannel.read(buffer);
        //关闭通道
        fileChannel.close();
        buffer.flip();
    }
}

使用Buffer完成文件的复制:

public class Nio_Buffer_Copy {
    public static void main(String[] args) throws IOException {
        //输出流对象
        FileOutputStream fout = new FileOutputStream("d:/c.txt");
        //输入流对象
        FileInputStream fin = new FileInputStream("d:/a.txt");
        //输出流的通道,数据的目的地
        FileChannel writeChannel = fout.getChannel();
        //输入流的通道,数据的源头
        FileChannel readChannel = fin.getChannel();
        //Buffer对象
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(true){
            buffer.clear();
            //返回读取数据的大小
            int len = readChannel.read(buffer);
            if(len == -1){
                break;
            }
            buffer.flip();
            writeChannel.write(buffer);
        }
    }
}

结果:

0
11
0
11
0

六)、深入学习Buffer

主要属性:

//标志位
private int mark = -1;
//写模式:当前缓冲区的位置,从Position的下一个位置写数据
//读模式:当前缓冲区的读位置,将从此位置后,读取数据
private int position = 0;
//写模式:  缓冲区的实际上限,总是小于等于容量,通常等于容量
//读模式: 代表可读取的总容量,和上次写入的数据量相等
private int limit;
//写模式: 缓冲区的总容量上限
//读模式: 缓冲区的总容量上限
private int capacity;

对Buffer进行claer()和flip()操作时lmint和position的变化

public class Filp_Clear {
    public static void main(String[] args) {
        //创建具有15个字节的Buffer对象
        ByteBuffer buffer = ByteBuffer.allocate(15);
        System.out.println("存入元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        //向Buffer中存入数据
        for(int i = 0 ; i < 10 ; i++){
            buffer.put((byte)i);
        }
        //存入元素后position和limit的变化
        System.out.println("存入元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        buffer.flip();
        //flip后position和limit的变化
        System.out.println("flip后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        for(int i = 0 ; i < 5 ; i++){
            System.out.print(buffer.get()+" ");
        }
        System.out.println();
        //读取Buffer元素后position和limit的变化
        System.out.println("读取Buffer元素后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        buffer.rewind();
        System.out.println("rewind==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        buffer.flip();
        //第二次flip后position和limit的变化
        System.out.println("第二次flip后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());
        buffer.clear();
        //clear后position和limit的变化
        System.out.println("clear后position和limit的变化==>"+"position:"+buffer.position()+" limit:"+buffer.limit()+" capacity:" +buffer.capacity());

    }
}

运行结果:

存入元素后position和limit的变化==>position:0 limit:15 capacity:15
存入元素后position和limit的变化==>position:10 limit:15 capacity:15
flip后position和limit的变化==>position:0 limit:10 capacity:15
0 1 2 3 4 
读取Buffer元素后position和limit的变化==>position:5 limit:10 capacity:15
rewind==>position:0 limit:10 capacity:15
第二次flip后position和limit的变化==>position:0 limit:0 capacity:15
clear后position和limit的变化==>position:0 limit:15 capacity:15

结果分析:

1).当第一次创建Buffer对象时

    position = 0, capacity = limit = Buffer数组容量大小

2).往Buffer添加数据

   position = 数组所占数据的大小,capacity = limit = Buffer数组容量大小

3).buffer.flip()操作

    position = 0, limit = 数组中所占元素的大小,即原position值, capacity =  Buffer数组容量大小

4).buffer.get()获取元素

   position = 获取元素的个数,limit = 数组中所占元素的大小,capacity =  Buffer数组容量大小

5).再次buffer.flip()

    position = 获取元素的个数,limit = position值,  capacity =  Buffer数组容量大小

    注: 当执行flip操作,limit值总是等于上一次的position值

6).buffer.clear

  position = 0, capacity = limit = Buffer数组容量大小

总结:

   i.  put():  position = 数组元素个数 , limit 和 capacity 不变

   ii.  flip(): position = 0,   limit = 原position值,  capacity 不变

   iii. rewind(): position = 0, limit 和 capacity 不变

   iiii.  claer(): 回到初始状态,position = 0, capacity = limit = Buffer数组容量大    小。

以上是关于NIO流的学习的主要内容,如果未能解决你的问题,请参考以下文章

Java NIO

对NIO的初步理解

java NIO 学习笔记

JavaJava NIO

Java NIO 缓冲区学习笔记

Java NIO和IO的区别