Java NIO 之Buffer

Java NIO 之Buffer

介绍

就速度而言CPU>内存>磁盘,而Buffer扮演的就是内存角色。

为了能够提高IO操作的性能,java定义了一个Buffer对象来表示内存块,其实本质上就是一个字节数组,但是其有更加简便的方法读取和写入数据操作方法。

在Java NIO中所有读取和写入数据操作都是基于Buffer完成的,在使用nio过程中请忘记输入流/输出流概念。

在java io中流是分方向的输入/输出流,而nio中不管是读取还是写入都是从管道中操作的。

java中Buffer抽象对象有很多其子类对象,除了boolean其余其中基本数据类型都有其对应的XXXBuffer抽象类。

其中当属ByteBuffer最为重要,因为其可以操作任意数据类型文件,因此我们也对其展开研究和学习。

ByteBuffer对应的实现类有两个,HeapByteBuffer 是基于Java堆的实现,而 DirectByteBuffer 则使用了 unsafe 的API进行了堆外的实现。

Buffer常用方法

/**
 * A container for data of a specific primitive type.
 */

public abstract class Buffer {

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;//游标
    private int position = 0;//当前位置
    private int limit;//上限
    private int capacity;//buffer容器容量,capacity通常定义完之后就不会再变化了。


    /**
     * Returns this buffer's capacity.
     */
    public final int capacity() {
        return capacity;
    }

    /**
     * Returns this buffer's position.
     */
    public final int position() {
        return position;
    }

    /**
     * Returns this buffer's limit.
     *
     * @return  The limit of this buffer
     */
    public final int limit() {
        return limit;
    }

    /**
     * Flips this buffer.  The limit is set to the current position and then
     * the position is set to zero.  If the mark is defined then it is
     * discarded.
     *
     * This method is often used in conjunction with the {@link
     * java.nio.ByteBuffer#compact compact} method when transferring data from
     * one place to another.
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

    /**
     * Tells whether there are any elements between the current position and
     * the limit. 
     */
    public final boolean hasRemaining() {
        return position < limit;
    }

    /**
     * Returns the number of elements between the current position and the
     * limit.
     */
    public final int remaining() {
        return limit - position;
    }

    /**********************************************************************/

    /**
     * Sets this buffer's position.  If the mark is defined and larger than the
     * new position then it is discarded.
     */
    public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }

    /**
     * Sets this buffer's limit.  If the position is larger than the new limit
     * then it is set to the new limit.  If the mark is defined and larger than
     * the new limit then it is discarded.
     */
    public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }

    /**
     * Sets this buffer's mark at its position.
     */
    public final Buffer mark() {
        mark = position;
        return this;
    }

    /**
     * Resets this buffer's position to the previously-marked position.
     */
    public final Buffer reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }

    /**
     * Clears this buffer.  The position is set to zero, the limit is set to
     * the capacity, and the mark is discarded.
     */
    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

    /**
     * Rewinds this buffer.  The position is set to zero and the mark is
     * discarded.
     */
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

    /**
     * Returns the number of elements between the current position and the
     * limit.
     */
    public final int remaining() {
        return limit - position;
    }

    /**
     * Tells whether or not this buffer is read-only.
     */
    public abstract boolean isReadOnly();


}

ByteBuffer常用方法

public abstract class ByteBuffer
extends Buffer
implements Comparable<ByteBuffer>
{

    // These fields are declared here rather than in Heap-X-Buffer in order to
    // reduce the number of virtual method invocations needed to access these
    // values, which is especially costly when coding small buffers.
    //
    final byte[] hb;                  // Non-null only for heap buffers
    final int offset;
    boolean isReadOnly;                 // Valid only for heap buffers

    /**
     * Allocates a new byte buffer.
     *
     * The new buffer's position will be zero, its limit will be its
     * capacity, its mark will be undefined, and each of its elements will be
     * initialized to zero.
     *
     * 该方法主要用来instance ByteBuffer,很重要的一个方法。
     *
     */
    public static ByteBuffer allocate(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException();
        return new HeapByteBuffer(capacity, capacity);
    }

    /**
     * Relative get method.  Reads the byte at this buffer's
     * current position, and then increments the position.
     *
     */
    public abstract byte get();

    /**
     * Relative put method;(optional operation).
     *
     * Writes the given byte into this buffer at the current
     * position, and then increments the position. 
     */
    public abstract ByteBuffer put(byte b);

     /**
     * Relative bulk get method.
     */
    public ByteBuffer get(byte[] dst) {
        return get(dst, 0, dst.length);
    }

    /**
     * Relative bulk put method;(optional operation).
     *
     * This method transfers the entire content of the given source
     * byte array into this buffer.  An invocation of this method of the
     * form dst.put(a) behaves in exactly the same way as the
     * invocation
     */
    public final ByteBuffer put(byte[] src) {
        return put(src, 0, src.length);
    }

    /**
     * Allocates a new direct byte buffer.
     */
    public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
    }

     /**
     * Wraps a byte array into a buffer.
     *
     * 该方法也是用来实例化ByteBuffer对象,和allocate(int capacity)目的一样。
     */
    public static ByteBuffer wrap(byte[] array) {
        return wrap(array, 0, array.length);
    }

    /**
    *Compacts this buffer
    */
    public abstract ByteBuffer compact();

}

基于ByteBuffer深入理解读取和写入数据原理

//1、初始化ByteBuffer
ByteBuffer buffer=ByteBuffer.allocate(10);

position=0
limit=10 //初始化时limit等于buffer的容量
capacity=10 //初始化容量

//2、往buffer里写入数据
buffer.put("python".getBytes());
//每写入一个字节就会使position往后移动一位
position=6
limit=10
capacity=10

//3、当需要从buffer中读取数据时,需要调用flip()方法。
//flip方法是将limit移动到position位置,将position位置移动到buffer开始位置即下标0。
position=0
limit=6
capacity=10

分析从buffer中读取数据时为什么需要调用flip()方法
如果不调用flip()方法,那么position为6,limit为10,由于调用buffer.get()方法是从position位置开始一直往下读数据,直到limit位置,那么读出来的数据就是0、0、0、0(默认初始化时就是全部填充0)

只有调用了flip之后,position设置为0,limit设置为6,那么循环调用buffer.get()方法时,才能取出python数据。limit就是限制从buffer中取数的

ByteBuffer buffer = ByteBuffer.allocate(10);
    // buffer对象中写入数据
    buffer.put("Python".getBytes());
    buffer.flip();
    // buffer对象读取数据
    while (buffer.hasRemaining()) {
        System.out.print((char) buffer.get());
    }

备注:flip方法非常重要,每次从Buffer对象中读取数据时都要调用该方法。

//调用clear()方法
clear方法使得
position=0
limit=10
capacity=10

This method does not actually erase the data in the buffer, but it is named as if it did because it will most often be used in situations in which that might as well be the case.

备注:clear方法并不像其名字一样清空Buffer中的数据。

clear方法是用的场景并不多,大都数时候都是使用flip方法。

put方法

Buffer 的put 方法

写模式下,往buffer里写一个字节,并把postion移动一位。写模式下,一般limit与capacity相等

flip方法

Buffer 的flip 方法

写完数据,需要开始读的时候,将postion复位到0,并将limit设为当前postion。

get方法

Buffer 的get方法

从buffer里读一个字节,并把postion移动一位。上限是limit,即写入数据的最后位置

clear方法

Buffer 的clear方法

将position置为0,并不清除buffer内容

总结

Buffer是java nio中扮演很重要的一个角色,nio的操作都是基于Buffer来实现的。因此掌握并理解好Buffer非常的重要。

参考

1、http://tutorials.jenkov.com/java-nio/index.html
2、http://www.importnew.com/20061.html?utm_source=tuicool&utm_medium=referral
3、JDK源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值