一 前言

            在JAVA API提供的原I/O中,提供了文件读写,操作,传输的方法。但是存在一个核心的问题,就是这些文件的读写,操作等都是阻塞式,如果当前操作未完成,程序无法向下执行,所以在某种情况下会严重影响I/O,效率。因此,在后期的JDK版本发布中,出现了NIO,NIO包括对缓冲区操作,通道,文件锁,字符集,selector等。下面为大家介绍下缓冲区。

二  缓冲区

           缓冲区针对除boolean之外的所有基本数据类型都设置(ByteBuffer(仅其可直接缓冲区),CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer, LongBuffer,ShorBuffer)

           缓冲区中存在三个重要变量:position(在buffer执行flip()后重置为0),limit(在buffer执行flip后,为原position值),capactiy(缓冲区大小)

          position:写模式下写入数据的下标位(起始0,最大可为capacity),读写模式下为读入数据的下标位(起始0,最大为capacity),最大值可为-1.

           limit:  读模式下可以读取的最大数据,此时limit= position,写入模式能够写入多少数据,此时limit=capacity。

           capacity:缓冲区的容量。 

          方法:主要有下列常用方法

            alllocate(int length):设置缓冲区长度。

            put(Object o):放入缓冲区元素

            force(true):将缓冲区数据强制存储到磁盘中。

            get(Object o):获取缓冲区元素

            slice():创建子缓冲区

             wrap(byte[] array, int offset, int length):将数组放到缓冲区

    read(charbuffer target)将元素读入缓冲区

    flip()重新设置缓冲区,用于从一个缓冲区把数据传输到另一个缓冲区;实现缓冲区读写模式的切换。

    clear():清除缓冲区,postion=0,limit=capacity,把缓冲区已读取的数据清除。

    compact():清除缓冲区,将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。。

三 应用


1.对缓冲进行放入数据,获取元素:

package com.myd.cn.Nio;
 import java.nio.IntBuffer;

 /**
  * 缓冲区操作:对缓冲进行放入数据,获取元素
  * @author MAYADONG
  *
  */
 public class IntBuffer01 {
     public static void main(String[] args) {
    //设置缓冲区大小
     IntBuffer buf = IntBuffer.allocate(10);
     System.out.println("放入数据之前:position: "+buf.position()+",limit: "+buf.limit()+",capacity: "+buf.capacity());
     //放入数据
     int [] temp = {1,3,4,5};
     buf.put(temp);
     
     System.out.println("放入数据之后:position: "+buf.position()+",limit: "+buf.limit()+",capacity: "+buf.capacity());
     //重设缓冲区(将limit = (当前)positon,position = 0)
     buf.flip();
     System.out.println("flush之后:position: "+buf.position()+",limit: "+buf.limit()+",capacity: "+buf.capacity());
     System.out.println("输出缓冲区数据");
     //输出数据
     while(buf.hasRemaining()){
     System.out.print(buf.get());
     }
}
 }

java list 缓冲 java缓冲区技术_java list 缓冲

执行程序发现put()之后, postion = 4,limit = capacity = 10,flip()操作之后,发现 position = 0,limit = (原)postion ,capacity = 10;



2.同时读入文件内容,把内容写入其他文件

package com.myd.cn.Nio;


 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;


 public class FileChannel02 {
         public static void main(String[] args) throws IOException {
         //定义声明读写的文件路径 文件读写流,以及读写通道
        File read = new File("E:"+File.separator+"pay"+File.separator+"read.txt");
        File write = new File("E:"+File.separator+"pay"+File.separator+"write.txt");
        
        
        //定义输入,输出字节流,输入,输出通道
        FileInputStream input = null;
        FileOutputStream output = null;
        //输入输出通道
        FileChannel fin = null;
        FileChannel fout = null;
        
        
        //实例化各个变量
        input = new FileInputStream(read);
        output = new FileOutputStream(write, true);
        
        fin = input.getChannel();
        fout = output.getChannel();
        
        //因通道是在缓存区操作的,需要创建缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        
        System.out.println("position:  "+buf.position()+",limit:  "+buf.limit()+",capacity:  "+buf.capacity());
        
        int temp = 0;
        //将其迭代读取缓冲区
        while ((temp = fin.read(buf))!=-1) {
         //重置缓存区,重新读取   
         buf.flip();
              System.out.println("position:  "+buf.position()+",limit:  "+buf.limit()+",capacity:  "+buf.capacity());


        //将迭代读取的内容通过写入通道,放入缓存区
                fout.write(buf);      
              System.out.println("position:  "+buf.position()+",limit:  "+buf.limit()+",capacity:  "+buf.capacity());


       //清空缓冲区,再次进行读取,防止内存溢出
                 buf.clear();
        }
        
        try {
      fout.close();
      fin.close();
        } catch (Exception e) {
       e.printStackTrace();
        }
}
 }

java list 缓冲 java缓冲区技术_java list 缓冲_02


操作之后,发现读入文件内容时 limit = capacity;缓冲区重置后,limit < capacity;缓冲区清空后,position = limit



在把文件内容写入缓冲去时,要记得flip()缓冲区,进行文件内容的再次读取;

把文件写入缓冲区后,要记得clear()缓冲区,防止因缓冲区设置过小,而造成内存溢出(缓冲区也相当于内存)

3.设置子缓冲区

package com.myd.cn.Nio;


 import java.nio.IntBuffer;


 public class IntBuffer01 {
           public static void main(String[] args) {
 //设置缓冲区大小
          IntBuffer buf = IntBuffer.allocate(10);
          IntBuffer sub = null;
          //放入元素
          System.out.println("放入数据之前:position: "+buf.position()+",limit: "+buf.limit()+",capacity: "+buf.capacity());
          int [] temp = {1,3,4,5,33,23,4,64,44,6};
          buf.put(temp);
          System.out.println("放入数据之后:position: "+buf.position()+",limit: "+buf.limit()+",capacity: "+buf.capacity());
          //设置子缓冲区
          
          //设置子缓冲区position的值
          buf.position(2);
          //设置子缓冲区limit值
          buf.limit(5);
          
          //设置的position,limit区间为:左闭右开
          sub = buf.slice();
          
          //重设缓冲区
          buf.flip();
          //输出缓冲区
          System.out.println("子缓冲区的元素:    ");
          while (sub.hasRemaining()) {
 
         System.out.print(sub.get()+"\t");
}
}
 }

java list 缓冲 java缓冲区技术_System_03


观察发现,子缓冲区根据新设置的position和limit来界定输出,范围区间为左闭又开。



4.直接缓冲区:提高本机对I/O的操作性能

package com.myd.cn.Nio;


 import java.nio.ByteBuffer;


 /**
  * 直接缓冲区:在本机上尽可能的提高本机操作缓冲区的性能 
  * @author MAYADONG
  *
  */
 public class DirectBuffer {
        public static void main(String[] args) {
     //设置直接缓冲区
       ByteBuffer directBuf = ByteBuffer.allocateDirect(10);
       System.out.println("放入数据之前:position: "+directBuf.position()+",limit: "+directBuf.limit()+",capacity: "+directBuf.capacity());
       
       //设置值
       byte [] arry = {1,3,5,6,44,9,94,10,23};
       directBuf.put(arry);
       System.out.println("放入数据之后:position: "+directBuf.position()+",limit: "+directBuf.limit()+",capacity: "+directBuf.capacity());
       
       
       //重新设置缓冲区
       directBuf.flip();
       System.out.println("执行  flip() 之前:position: "+directBuf.position()+",limit: "+directBuf.limit()+",capacity: "+directBuf.capacity());
      
       
        //输出
        System.out.println("子缓冲区的元素:    ");
       while (directBuf.hasRemaining()) {
       System.out.print(directBuf.get()+"\t");

       }
    }
  }

java list 缓冲 java缓冲区技术_java list 缓冲_04

感觉和缓冲区一样,但是在性能上,使用直接缓冲区在理论上是提高程序性能。


四 总结

       旧有的I/O操作,是操作硬盘的数据,效率低。使用NIO后,可以把数据读入,写入到缓冲区,缓冲区接近内存读取速度,所以会有显著的性能提高。NIO实现了除Boolean之外的所有基础数据类型的缓冲区实现,可以满足以往的方法修改,迁移。