天天看點

Java IO:ByteArrayInputStream使用詳解及源碼分析

1 使用方法

  ByteArrayInputStream 包含一個内部緩沖區,該緩沖區包含從流中讀取的位元組。内部計數器跟蹤 read 方法要提供的下一個位元組。ByteArrayOutputStream實作了一個輸出流,其中的資料被寫入一個 byte 數組。緩沖區會随着資料的不斷寫入而自動增長。可使用 toByteArray()和 toString()擷取資料。

1.1 方法介紹

  ByteArrayInputStream提供的API如下:

// 構造函數
    ByteArrayInputStream(byte[] buf)
    ByteArrayInputStream(byte[] buf, int offset, int length)

    synchronized int         available() //能否讀取位元組流的下一位元組
    void                     close() //關閉位元組流
    synchronized void        mark(int readlimit) //儲存目前位置
    boolean                  markSupported() //是否支援mark
    synchronized int         read() //讀取下一位元組
    synchronized int         read(byte[] buffer, int offset, int length) //将位元組流寫入buffer數組
    synchronized void        reset() //重置索引到mark位置
    synchronized long        skip(long byteCount) //跳過n個位元組
}
           

1.2 使用示例

public class TestByteArray {
    // 對應英文字母“abcddefghijklmnopqrsttuvwxyz”
    private final byte[] ArrayLetters = {
            , , , , , , , , , , , , , , ,
            , , , , , , , , , , 
    };

    public void testByteArrayInputStream() {
        //建立位元組流,以ArrayLetters初始化
        ByteArrayInputStream inputStream = new ByteArrayInputStream(ArrayLetters);

        //讀取5個位元組
        int i = ;
        System.out.print("前5個位元組為: ");
        while (i++ < ) {
            //是否可讀
            if (inputStream.available() >= ) {
                int buf = inputStream.read();
                System.out.printf("0x%s ", Integer.toHexString(buf));
            }
        }
        System.out.println();

        //是否支援标記
        if (!inputStream.markSupported()) {
            System.out.println("該位元組流不支援标記");
        } else {
            System.out.println("該位元組流支援标記");
        }

        //标記, 已經讀取5個位元組,标記處為0x66
        System.out.println("标記該位元組流為位置為0x66(f)");
        inputStream.mark();

        //跳過2個位元組
        inputStream.skip();

        //讀取5個位元組到buffer
        byte [] buffer = new byte[];
        inputStream.read(buffer, , );
        System.out.println("buffer: " + new String(buffer));

        //重置
        inputStream.reset();
        inputStream.read(buffer, , );
        System.out.println("重置後讀取5個字元為: " + new String(buffer));
    }
}
           

  運作結果如下:

前個位元組為:     
該位元組流支援标記
标記該位元組流為位置為(f)
buffer: hijkl
重置後讀取個字元為: fghij
           

2 源碼分析

2.1構造函數

  ByteArrayInputStream有兩個構造函數,差別是初始化内容選擇。

/**
 * Creates a <code>ByteArrayInputStream</code>
 * so that it  uses <code>buf</code> as its
 * buffer array.
 * The buffer array is not copied.
 * The initial value of <code>pos</code>
 * is <code>0</code> and the initial value
 * of  <code>count</code> is the length of
 * <code>buf</code>.
 *
 * @param   buf   the input buffer.
 */
public ByteArrayInputStream(byte buf[]) {
    this.buf = buf; //緩沖數組
    this.pos = ; //目前位置
    this.count = buf.length; //輸入流位元組數
}

/**
 * Creates <code>ByteArrayInputStream</code>
 * that uses <code>buf</code> as its
 * buffer array. The initial value of <code>pos</code>
 * is <code>offset</code> and the initial value
 * of <code>count</code> is the minimum of <code>offset+length</code>
 * and <code>buf.length</code>.
 * The buffer array is not copied. The buffer's mark is
 * set to the specified offset.
 *
 * @param   buf      the input buffer.
 * @param   offset   the offset in the buffer of the first byte to read.
 * @param   length   the maximum number of bytes to read from the buffer.
 */
public ByteArrayInputStream(byte buf[], int offset, int length) {
    this.buf = buf; //緩沖數組
    this.pos = offset; //目前位置為傳入buf的offset
    this.count = Math.min(offset + length, buf.length); //輸入流位元組數
    this.mark = offset; //标記
}
           

2.2 read方法

  read方法有兩個,不帶參數的read()每次讀取位元組流中一個位元組,帶參數的read(byte b[], int off, int len)将位元組流從目前位置開始,寫入len個位元組到b中,寫入開始位置為off。

/**
 * 讀取位元組流目前位元組
 * @return 一個位元組
 */
public synchronized int read() {
    return (pos < count) ? (buf[pos++] & ) : -; //&0xff為限制傳回值為一個位元組,即8位
}

/**
 * 将位元組流目前位置開始的len個位元組寫入到 b從off開始的len個位置
 * @param b
 * @param off
 * @param len
 * @return
 */
public synchronized int read(byte b[], int off, int len) {
    if (b == null) {
        throw new NullPointerException();
    } else if (off <  || len <  || len > b.length - off) {
        throw new IndexOutOfBoundsException();
    }

    if (pos >= count) { //超出位元組流範圍
        return -;
    }

    int avail = count - pos; //可讀取的位元組數量
    if (len > avail) {
        len = avail;
    }
    if (len <= ) {
        return ;
    }
    System.arraycopy(buf, pos, b, off, len); //将buf從pos位置開始的位元組複制到b從off開始的位置,共複制len長
    pos += len;
    return len;
}
           

2.4 skip方法

/**
 * Skips <code>n</code> bytes of input from this input stream. Fewer
 * bytes might be skipped if the end of the input stream is reached.
 * The actual number <code>k</code>
 * of bytes to be skipped is equal to the smaller
 * of <code>n</code> and  <code>count-pos</code>.
 * The value <code>k</code> is added into <code>pos</code>
 * and <code>k</code> is returned.
 *
 * @param   n   the number of bytes to be skipped.
 * @return  the actual number of bytes skipped.
 */
public synchronized long skip(long n) {
    long k = count - pos; //剩餘位元組數
    if (n < k) {
        k = n <  ?  : n;
    }

    pos += k;
    return k;
}
           

2.5 mark和reset方法

/**
 * Set the current marked position in the stream.
 * ByteArrayInputStream objects are marked at position zero by
 * default when constructed.  They may be marked at another
 * position within the buffer by this method.
 * <p>
 * If no mark has been set, then the value of the mark is the
 * offset passed to the constructor (or  if the offset was not
 * supplied).
 *
 * <p> Note: The <code>readAheadLimit</code> for this class
 *  has no meaning.
 *
 * @since   JDK1
 */
public void mark(int readAheadLimit) {
    mark = pos;
}

/**
 * Resets the buffer to the marked position.  The marked position
 * is  unless another position was marked or an offset was specified
 * in the constructor.
 */
public synchronized void reset() {
    pos = mark;
}
           

參考:

[1] http://www.cnblogs.com/skywang12345/p/io_02.html

[2] http://www.cnblogs.com/skywang12345/p/io_03.html

[3] http://blog.csdn.net/rcoder/article/details/6118313