Java NIO-缓冲区操作

一 前言

            在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 NIO-缓冲区操作_第1张图片

执行程序发现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 NIO-缓冲区操作_第2张图片


操作之后,发现读入文件内容时 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 NIO-缓冲区操作_第3张图片


观察发现,子缓冲区根据新设置的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 NIO-缓冲区操作_第4张图片

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


四 总结

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


你可能感兴趣的:(java)