ByteBuffer使用實例


  ByteBuffer作為JDK的字節流處理對象,這里舉個小例子說明下用法,直接上代碼:

package com.wlf.netty.nettyserver;

import org.junit.Assert;
import org.junit.Test;

import java.nio.ByteBuffer;

public class ByteBufferTest {

    @Test
    public void byteBufferTest() {

        // 寫入消息體
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        byteBuffer.putInt(0xabef0101);
        byteBuffer.putInt(1024); // 今天過節
        byteBuffer.put((byte) 1);
        byteBuffer.put((byte) 0);

        // 讀取消息頭,因為寫完后position已經到10了,所以需要先反轉為0,再從頭讀取
        byteBuffer.flip();
        printDelimiter(byteBuffer);

        // 讀取length
        printLength(byteBuffer);

        // 繼續讀取剩下數據
        byteBuffer.get();
        byteBuffer.get();
        printByteBuffer(byteBuffer);

        // 我再反轉一下,我還可以從頭開始讀
        byteBuffer.flip();
        printDelimiter(byteBuffer);

        // clear清空一下,再從頭開始讀
        byteBuffer.clear();
        printDelimiter(byteBuffer);

        // rewind重繞一下
        byteBuffer.rewind();
        printDelimiter(byteBuffer);

        // mark標記一下
        byteBuffer.mark();

        // 再讀取length
        printLength(byteBuffer);

        // reset重置,回到讀取delimiter的地方
        byteBuffer.reset();
        printByteBuffer(byteBuffer);
    }

    private void printDelimiter(ByteBuffer buf) {
        int newDelimiter = buf.getInt();
        System.out.printf("delimeter: %s\n", Integer.toHexString(newDelimiter));
        printByteBuffer(buf);
    }

    private void printLength(ByteBuffer buf) {
        int length = buf.getInt();
        System.out.printf("length: %d\n", length);
        printByteBuffer(buf);
    }

    private void printByteBuffer(ByteBuffer buf) {
        System.out.printf("position: %d, limit: %d, capacity: %d\n", buf.position(), buf.limit(), buf.capacity());
    }
}

  輸出結果:

delimeter: abef0101
position: 4, limit: 10, capacity: 10
length: 1024
position: 8, limit: 10, capacity: 10
position: 10, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
delimeter: abef0101
position: 4, limit: 10, capacity: 10
length: 1024
position: 8, limit: 10, capacity: 10
position: 4, limit: 10, capacity: 10

Process finished with exit code 0

   ByteBuffer的索引是唯一的。像上面的例子,初始索引是0,寫完索引值為9,為了讀取寫入的值,我們再重新設置索引為0(調用flip方法)。ByteBuffer有4個索引值,分別是:

  mask:就是你標記的索引,標記唯一的作用是調用reset重置回到過去

  position:當前位置的索引,mask標記任何時候都不會大於position,因為你必須先讀到當前位置之后,才能標記該位置;同時position也不能超過limit限制

  limit:第一個不應該讀取或寫入的元素的索引,也就是讀寫禁地,默認是最大容量,如果你設置該值,那么理所讓然它不能超過最大容量capacity

  capacity:這個就不解釋了

  它們的大小關系始終是:

  mask <= position <= limit <= capacity

  我們上面的例子中就是capacity=limit。

  初始索引:

  +-----------------------------------------------------+

       /                            bytes                              /

       +-----------------------------------------------------+

       /                            10                                  /

  0=position                                               10=limit=capacity

 

  我們寫入delimiter之后:

  +----------------+------------------------------------+

       /      delimiter /     other  bytes                       /

       +----------------+------------------------------------+

       /             4     /          6                                    /

   0        4=position                                     10=limit=capacity

  

  至於反轉flip如何切換讀寫模式、reset如何重置標記、clear清除如何重新設置索引值為0、rewind重繞如何讓你重新讀取,都不會動內容,所以你會看到上面不管怎么折騰我們都可以重復取出delimiter、length的值。看下源碼就一清二楚了,無非就是對上面4個索引值進行賦值而已:

    /**
     * Resets this buffer's position to the previously-marked position.
     *
     * <p> Invoking this method neither changes nor discards the mark's
     * value. </p>
     *
     * @return  This buffer
     *
     * @throws  InvalidMarkException
     *          If the mark has not been set
     */
    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.
     *
     * <p> Invoke this method before using a sequence of channel-read or
     * <i>put</i> operations to fill this buffer.  For example:
     *
     * <blockquote><pre>
     * buf.clear();     // Prepare buffer for reading
     * in.read(buf);    // Read data</pre></blockquote>
     *
     * <p> 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. </p>
     *
     * @return  This buffer
     */
    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

    /**
     * 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;
    }

    /**
     * Rewinds this buffer.  The position is set to zero and the mark is
     * discarded.
     *
     * <p> Invoke this method before a sequence of channel-write or <i>get</i>
     * operations, assuming that the limit has already been set
     * appropriately.  For example:
     *
     * <blockquote><pre>
     * out.write(buf);    // Write remaining data
     * buf.rewind();      // Rewind buffer
     * buf.get(array);    // Copy data into array</pre></blockquote>
     *
     * @return  This buffer
     */
    public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM