美文网首页
JAVA NIO - Buffer

JAVA NIO - Buffer

作者: ilaoke | 来源:发表于2018-06-10 17:50 被阅读9次

NIO是基于Buffer的,通过channel将buffer中的内容发送给IO或保存从IO中读取的内容到buffer。

Buffer有以下属性:

  1. Capacity,表示buffer可保存的数据项大小,容量在buffer创建时指定且之后无法更改。
  2. Limit,从0开始的索引位置,从此索引及之后的 位置不应该被读取或写入。
  3. Position,从0开始的索引位置,表示下次读取或写入数据的位置。
  4. Mark,从0开始的索引位置,表示一个标记位,将调用reset()方法时会使用该位置。

这四个值的关系是:capacity >= limit >= position >= mark

所有的buffer都是可读的,但不一定都是可写入的,如果向只读的buffer写入数据,就会报ReadOnlyBufferException 异常,通过isReadOnly() 方法可以判断buffer是否是只读的。

buffer 不是线程安全的,如果要多线程同时访问,需要我们来保证线程同步。

每一种基本类型都有对应的Buffer子类,除了Boolean类型: ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, and ShortBuffer .

ByteBuffer创建及读写

我们以ByteBuffer为例,以下列出buffer的一些基本操作,以及这些操作对position/limit的影响。

// 创建ByteBuffer,buffer中的值默认初始化为0
ByteBuffer buffer = ByteBuffer.allocate(7);
// 向buffer中添加四个值
buffer.put((byte) 10).put((byte) 20).put((byte) 30).put((byte) 40);

System.out.println(buffer.limit()); // 7
System.out.println(buffer.position()); // 4
System.out.println(buffer.capacity()); // 7
System.out.println(buffer.arrayOffset()); // 0

buffer.limit(5); // 设置limit为5

System.out.println(buffer.limit()); // 5
System.out.println(buffer.position()); // 4
System.out.println(buffer.capacity()); // 7
System.out.println(buffer.arrayOffset()); // 0

// 读取当前position的值,然后position++
System.out.println(buffer.get()); // 0
System.out.println(buffer.position()); // 5

buffer.position(0); // 设置position到0
System.out.println(buffer.get()); // 10
System.out.println(buffer.get()); // 20
System.out.println(buffer.position()); // 2
buffer_basic.png

flip()

flip()方法将limit设置为position, position设置为0.

    /**
     * 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.
     *
     * <p> After a sequence of channel-read or <i>put</i> operations, invoke
     * this method to prepare for a sequence of channel-write or relative
     * <i>get</i> operations.  For example:
     *
     * <blockquote><pre>
     * buf.put(magic);    // Prepend header
     * in.read(buf);      // Read data into rest of buffer
     * buf.flip();        // Flip buffer
     * out.write(buf);    // Write header + data to channel</pre></blockquote>
     *
     * <p> This method is often used in conjunction with the {@link
     * java.nio.ByteBuffer#compact compact} method when transferring data from
     * one place to another.  </p>
     *
     * @return  This buffer
     */
    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

执行flip()方法后,channel就可以从buffer中开始读取数据。

rewind()方法类似flip()方法,但是忽略limit的设置:

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

mark()和reset()

mark方法用来标记当前position,当执行reset时,将position恢复成上次标记的position。

// 创建ByteBuffer,buffer中的值默认初始化为0
ByteBuffer buffer = ByteBuffer.allocate(7);
// 向buffer中添加四个值
buffer.put((byte) 10).put((byte) 20).put((byte) 30).put((byte) 40);

System.out.println(buffer.position()); // 4
System.out.println(buffer.limit()); // 7
System.out.println(buffer.capacity()); // 7

// 将limit设置为4
buffer.limit(4);
// 将mark设置为1
buffer.position(1).mark().position(3);
System.out.println(buffer.get()); // 40

// reset将position设置为mark标记的位置
buffer.reset();
System.out.println(buffer.get()); // 20

下图说明上面代码导致的mark,position和limit的变化过程。

mark_reset.png

reset()与clear()方法的区别:

reset是将positon设置为上次标记的position位置,而clear将position直接设置为0并将limit设置为capacity.

compact()

该方法将从当前position到limit这之间的数据,依次移动到buffer的开始位置。

compact.png

在将buffer中的数据写出去时,为了避免buffer中的数据没有被完全被写出,可以执行compact方法将未写出的数据移动到buffer头部,当再读数据到buffer中时,后续读入的数据就会跟在之前未写出的数据之后。

buf.clear();          // Prepare buffer for use
while (in.read(buf) >= 0 || buf.position != 0) {
    buf.flip();
    out.write(buf);
    buf.compact();    // In case of partial write
}

相关文章

网友评论

      本文标题:JAVA NIO - Buffer

      本文链接:https://www.haomeiwen.com/subject/ktcqeftx.html