Java NIO学习——Buffer学习

概述

基本属性

一个缓冲区Buffer有四个属性,容量(Capacity),上界(limit),位置(position),标记(mark)。

属性名读模式含义写模式含义备注
容量(Capacity)Buffer的容量就是一个Buffer所最多能容纳的数据长度。同读模式Buffer在创建之后,容量便不会再变化
上界(limit)limit表示Buffer最多能读到多少数据。limit表示最多能往Buffer写入的数据量,此时,limit等于Buffer的capacity当切换Buffer到读模式时,limit会被设置成写模式下的position值;表示可读数据的结束位置
位置(position)position表示开始读取数据的位置,当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。当position=limit时,表示Buffer已无数据可读position表示当前待写入的位置。初始position值为0,当数据写入后,position会递增,position的max值为capacity – 1
标记(mark)mark(标记)是一个备忘位置,在初始化的时候,mark是未定义的值,在调用mark()函数后,设置mark=postion;等Buffer的position变化后,通过reset()函数,可以重新设置position=mark读写模式相同mark只是提供了一种position备份功能

Buffer模式

在Java中,一个缓冲区有两种模式,写模式(write mode)和读模式(Read Mode)。
当Buffer处于写模式的时候,表示当前Buffer等待写入数据,当一个Buffer初始化的时候,是处于写模式的。当Buffer达到容量最大值时,Buffer便不能再写入数据,如果继续写入,则会抛出BufferOverflowException异常,表示,Buffer已经写满。

当Buffer写完数据之后,可以切换到读模式,读模式表示可以从Buffer读取数据。如果Buffer内容已经读完,继续读取Buffer,则会抛出BufferUnderflowException异常。

模式切换函数

函数名作用
filp将Buffer从写模式切换到读模式
clear将Buffer从读模式切换到写模式,同时清空Buffer内所有数据
compact将Buffer从读模式切换到写模式,只清空已读数据,保留未读数据

例子

下面以CharBuffer为例看下Buffer基本读写方式,以及对应的属性。

public class LearnBuffer {
    static void bufferP(){
        CharBuffer charBuffer = CharBuffer.allocate(64);
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position());
        charBuffer.append("This is a test.");
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        System.out.println("\nBegin test read mode. ---------");
        charBuffer.flip();
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        System.out.print(charBuffer.get());
        System.out.println(charBuffer.get());
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        // mark当前位置
        charBuffer.mark();
        while (charBuffer.hasRemaining()){
            System.out.print(charBuffer.get());
        }
        System.out.println();
        try {
            System.out.println(charBuffer.get());
        }catch (java.nio.BufferUnderflowException e){
            System.out.println("Get a java.nio.BufferUnderflowException.");
        }

        System.out.println("\nBegin test mark,reset. ---------");
        // 将位置重置为之前mark的位置
        charBuffer.reset();
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        while (charBuffer.hasRemaining()){
            System.out.print(charBuffer.get());
        }
        System.out.println();

        System.out.println("\nBegin test compact. ---------");
        // 将位置重置为之前mark的位置
        charBuffer.reset();
        // 将已读数据清除,保留未读数据
        charBuffer.compact();
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        charBuffer.flip();
        while (charBuffer.hasRemaining()){
            System.out.print(charBuffer.get());
        }
        System.out.println();

        System.out.println("\nBegin test clear. ---------");
        //读完数据之后,可以调用clear将Buffer切换到写模式,同时删除之前所有数据
        charBuffer.clear();
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
    }

    public static void main( String[] args ) throws IOException {
        bufferP();
    }
}

下面是上面程序的输出结果

Capacity:64, limit:64, position:0
Capacity:64, limit:64, position:15

Begin test read mode. ---------
Capacity:64, limit:15, position:0
Th
Capacity:64, limit:15, position:2
is is a test.
Get a java.nio.BufferUnderflowException.

Begin test mark,reset. ---------
Capacity:64, limit:15, position:2
is is a test.

Begin test compact. ---------
Capacity:64, limit:64, position:13
is is a test.

Begin test clear. ---------
Capacity:64, limit:64, position:0

创建缓冲区

Java语言提供了8种缓存区。除了MappedByteBuffer是内存映射,其他7种对应了Java的7种内置类型。7种对应内置类型的Buffer都是抽象类,不能直接用new进行实例化。这7个类提供了相应的静态工厂方法来创建相应的类。每个类的工厂方法名都是相同的。

Java提供了静态工厂方法,用于新建Buffer对象。

allocate 方法可以分配一个指定容量的Buffer,
wrap 会直接传入一个数组,则Buffer并不会再分配新的内存创建缓冲区,而是直接使用传入的数组作为缓存区,创建的Buffer类的capacity为数组的长度,使用Buffer类的操作,都会直接影响到传入的数组,比如,Buffer.put了一个字符,则可以直接通过数组得到。

public class LearnBuffer {
    static void createBuffer(){
        char[] chars = new char[64];
        CharBuffer charBuffer = CharBuffer.wrap(chars);
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        charBuffer.append('a');
        System.out.println(chars[0]);
    }

    public static void main( String[] args ) {
        createBuffer();
    }
}

wrap 函数有两个版本,一个是直接传入一个数组,则buffer的position为0,limit为capacity;还有一种带有offset和length的版本,则buffer的position为offset,limit为length。

public class LearnBuffer {
    static void createBuffer(){
        char[] chars = new char[64];
        CharBuffer charBuffer = CharBuffer.wrap(chars, 2, 16);
        System.out.println("Capacity:"+charBuffer.capacity()+", limit:"+charBuffer.limit()
                +", position:"+charBuffer.position() );
        charBuffer.append('a');
        System.out.println(chars[2]);

        CharBuffer charBuffer1 = CharBuffer.wrap(chars);
        System.out.println("Capacity:"+charBuffer1.capacity()+", limit:"+charBuffer1.limit()
                +", position:"+charBuffer1.position());
    }

    public static void main( String[] args ) {
        createBuffer();
    }
}

复制缓存区

duplicate 函数

duplicate()函数创建一个与原始缓冲区相似的新缓冲区,新缓冲区共享旧缓冲区的数据和容量,但却有自己的position和limit。

public class LearnBuffer {
    static void duplicateBuffer(){
        CharBuffer charBuffer = CharBuffer.allocate(64);
        charBuffer.append("This is a duplicate test.");
        System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        CharBuffer newBuffer = charBuffer.duplicate();
        System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        charBuffer.flip();
        System.out.println("After charBuffer flip, charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("After charBuffer flip, newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        System.out.println(charBuffer.get(0));
        newBuffer.put(0, 'H');
        System.out.println(charBuffer.get(0));
    }

    public static void main( String[] args ) {
        duplicateBuffer();
    }
}

asReadOnlyBuffer()函数生成一个只读的缓冲区,和duplicate函数一样,新的只读缓冲区,和之前缓冲区共享数据和容量,各自拥有自己的position和limit。但只读缓冲区是不能调用put函数,否则会抛出ReadOnlyBufferException异常。

public class LearnBuffer {
    static void readOnlyBuffer(){
        CharBuffer charBuffer = CharBuffer.allocate(64);
        charBuffer.append("This is a readonly test.");

        CharBuffer newBuffer = charBuffer.asReadOnlyBuffer();

        System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        charBuffer.flip();
        System.out.println("After charBuffer flip, charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("After charBuffer flip, newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        try {
            newBuffer.append('a');
        }catch (ReadOnlyBufferException e){
            System.out.println("Get an java.nio.ReadOnlyBufferException");
        }
    }

    public static void main( String[] args ) {
        readOnlyBuffer();
    }
}

slice()函数也是产生新的缓冲区,并且与旧缓冲区共享数据,但slice()产生的缓冲区的容量是原缓冲区limit-position

static public void sliceBuffer(){
        CharBuffer charBuffer = CharBuffer.allocate(64);
        charBuffer.append("This is a slice test.");

        CharBuffer newBuffer = charBuffer.slice();

        System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        charBuffer.append("Add new string.");
        System.out.println(newBuffer.get(0));

        System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("newBuffer capacity:"+newBuffer.capacity()+", position:"+newBuffer.position()+", limit:"+newBuffer.limit());

        charBuffer.flip();
        CharBuffer newBuffer2 = charBuffer.slice();
        System.out.println("charBuffer capacity:"+charBuffer.capacity()+", position:"+charBuffer.position()+", limit:"+charBuffer.limit());
        System.out.println("newBuffer2 capacity:"+newBuffer2.capacity()+", position:"+newBuffer2.position()+", limit:"+newBuffer2.limit());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值