zoukankan      html  css  js  c++  java
  • JAVA NIO系列(三) Buffer 解读

    缓冲区分类 

    NIO中的buffer用于和通道交互,数据是从通道读入缓冲区,从缓冲区中写入通道的。Buffer就像一个数组,可以保存多个类型相同的数据。每种基本数据类型都有对应的Buffer类:

    缓冲区的属性

    1、capacity(容量):buffer本质是一个数组,在初始化时有固定的大小,这个值就是容量。容量不可改变,一旦缓冲区满了,需要将其清空才能将继续进行读写操作。

    2、position(位置):表示当前的位置,初始化时为0,当一个基本数据类型的数据写入buffer时,position会向前移动到下一个可插入数据的Buffer单元。position最大值可以是                              capacity-1。

    3、limit(限制):在缓冲区写模式下,limit表示你最多能往Buffer里写多少数据,大小等于capacity;在缓冲区读模式下,limit表示能从缓冲区内读取到多少数据,因此,当切          换Buffer到读模式时,limit会被设置成写模式下的position值。

                              

    一、使用NIO进行文件内容的复制:

    public class BufferTest
    {
        public static void main(String[] args) throws Exception
        {
            FileInputStream fis = new FileInputStream("d:/in.txt");
            FileChannel channel = fis.getChannel();
            
            FileOutputStream fos = new FileOutputStream("d:/out.txt");
            FileChannel channel1 = fos.getChannel();
            //初始化缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(20);
            System.out.println("通道文件的大小:" + channel.size());
            System.out.println("缓冲区初始化时当前位置:" + buffer.position());
            System.out.println("缓冲区初始化时可写的限制:" + buffer.limit());
            System.out.println("---------循环开始-----");
            //判断通道内数据是否读取完成
            while(-1 != channel.read(buffer))
            {
                System.out.println("缓冲区写模式下当前位置:" + buffer.position());
                System.out.println("缓冲区写模式下的限制:" + buffer.limit());
                //将缓冲区从写模式切换到读模式
                buffer.flip();
                System.out.println("缓冲区读模式下当前位置:" + buffer.position());
                System.out.println("缓冲区读模式下的限制:" + buffer.limit());
                //判断缓冲区内是否还有数据可读取
                while(buffer.hasRemaining())
                {
                    channel1.write(buffer);
                }
                buffer.clear();
            }
            channel.close();
            channel1.close();
            fis.close();
        }
    }

    执行结果:

    通道文件的大小:36
    缓冲区初始化时当前位置:0
    缓冲区初始化时可写的限制:20
    ---------循环开始-----
    缓冲区写模式下当前位置:20
    缓冲区写模式下的限制:20
    缓冲区读模式下当前位置:0
    缓冲区读模式下的限制:20
    缓冲区写模式下当前位置:16
    缓冲区写模式下的限制:20
    缓冲区读模式下当前位置:0
    缓冲区读模式下的限制:16

    1、文件的大小为36个字节,缓冲区初始化的大小为20个字节,程序中进行了两次读取操作,才完成了文件内容的复制。

    2、可以看到,在缓冲区写模式下,limit的大小始终等于capacity;而在读模式下,limit等于模式切换前position的大小。

    二、Buffer的分配

    Buffer对象的获取需要进行分配,每种类型的Buffer对象都有一个allocate方法。我们以程序中的ByteBuffer对象为例:

    ByteBuffer buffer = ByteBuffer.allocate(20);

    我们去跟踪下源码:

    1  public static ByteBuffer allocate(int capacity) {
    2     if (capacity < 0)
    3         throw new IllegalArgumentException();
    4     return new HeapByteBuffer(capacity, capacity);
    5     }
    HeapByteBuffer(int cap, int lim) {        // package-private
    
        super(-1, 0, lim, cap, new byte[cap], 0);

    //在这里已经创建一个以cap为大小的字节数组(new byte[cap])

    ByteBuffer(int mark, int pos, int lim, int cap,    // package-private
             byte[] hb, int offset)
        {
        super(mark, pos, lim, cap);
        this.hb = hb;
        this.offset = offset;
        }
    Buffer(int mark, int pos, int lim, int cap) {    // package-private
        if (cap < 0)
            throw new IllegalArgumentException();
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
            throw new IllegalArgumentException();
            this.mark = mark;
        }
        }

    //数组的创建在ByteBuffer类里面已经创建,在父类Buffer里,初始化容量、限制、位置等一些公共属性。

    三、Buffer模式的切换

    buffer.flip()该方法是用于将缓冲区从写模式切换到读模式,这是一种固定写法,该方法的源码如下:

    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
        }

     调用flip()方法会将position设回0,并将limit设置成之前position的值。

    四、remaind方法

    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
        }

    将position的位置设置为0,表示可以重新读取Buffer中的所有数据,limit保持不变。

    五、clear方法

    1  public final Buffer clear() {
    2     position = 0;
    3     limit = capacity;
    4     mark = -1;
    5     return this;

    1、一旦完成对buffer中数据的读取,需要让buffer做好再次被写入的准备,这时候可以调用clear方法来完成。

    2、clear方法将position设置为0,limit设置为容量的值,也就意味着buffer被清空了,但是这个清空的概念是写入数据可以从缓冲区的指定位置开始,但buffer里面的数据并没有        删除。

    3、如果buffer里面还有数据没有被读取,这个时候调用clear方法会导致那些数据被“遗忘”,因为没有标记告诉你哪些是读取过哪些没有被读取。

    六、向buffer中写入数据

    1、通过channel写入;

    2、通过buffer的put方法写入:

    buffer.put("channel".getBytes());

    七、从buffer中读取数据

    1、通过channel读取;

    2、通过buffer的get方法读取:

    byte b = buffer.get();
  • 相关阅读:
    android之APN
    Simple XML
    Retrofit – Java(Android) 的REST 接口封装类库
    Android 删除短信
    解决android:background背景图片被拉伸问题
    人分三等,你是哪一等?
    将android中的sample例子到eclipse中
    linux内存管理
    Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚(转)
    使用maven创建web项目
  • 原文地址:https://www.cnblogs.com/dongguacai/p/5812831.html
Copyright © 2011-2022 走看看