java.io包中的 ByteArrayInputStream 類可用於讀取輸入數組(字節)。

要創建字節數組輸入流,我們必須首先導入java.io.ByteArrayInputStream包。導入包後,我們有兩個構造函數可用於創建輸入流:


ByteArrayInputStream input = new ByteArrayInputStream(arr);
ByteArrayInputStream input = new ByteArrayInputStream(arr, 2, 2);
    

類裡面有4個字段:


// Byte array provided by the creator of the stream
protected byte buf[];

// Index of the next character to read from the input stream's buffer
protected int pos;

// Current marked position in the stream
protected int mark = 0;

// Index is one greater than the last valid character in the input stream's buffer
protected int count;
    

這是我們的構造函數:


public ByteArrayInputStream(byte buf[]) {
    this.buf = buf;
    this.pos = 0;
    this.count = buf.length;
}

public ByteArrayInputStream(byte buf[], int offset, int length) {
    this.buf = buf;
    this.pos = offset;
    this.count = Math.min(offset + length, buf.length);
    this.mark = offset;
}
    

ByteArrayInputStream 類的方法

方法 行動
內部讀取() 從此輸入流中讀取下一個字節的數據。
int read(byte b[], int off, int len) 從輸入流中讀取幾個字節並將它們存儲在緩衝區數組b中。
off是目標數組b的偏移量。
len是要讀取的最大字節數。
長跳過(長n) 跳過此輸入流中的 n 個字節的輸入。返回跳過的字節數(如果我們到達輸入流的末尾,它可能小於 n)。
內部可用() 返回可以從此輸入流中讀取(或跳過)的剩餘字節數。
無效重置() 將緩衝區重置為標記位置。標記的位置為 0,除非標記了另一個位置或在構造函數中指定了不同的偏移量。
布爾標記支持() 檢查此InputStream是否支持標記/重置。ByteArrayInputStream返回true
無效關閉() 什麼都不做。
無效標記(int readAheadLimit) 設置標記等於當前位置的字段。如果調用了reset方法,那麼後續的讀取將從該位置開始。readAheadLimit參數未使用且不影響該方法的行為

讓我們仔細看看這些方法,看看它們在實踐中是如何工作的。

讀()

當您想像從普通InputStream讀取字節一樣從ByteArrayInputStream讀取字節時,可以使用read()方法。


public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       for (int i = 0; i < array.length; i++) {
           int data = input.read();
           System.out.print(data + ", ");
       }
   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

可用的()

如果你想檢查你的緩衝區中是否有東西,你可以調用available()方法。


public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       System.out.println("Bytes available for reading: " + input.available());

       input.read();
       System.out.println("Bytes available for reading " + input.available());

       input.read();
       System.out.println("Bytes available for reading " + input.available());
   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

我們將看到每次從緩衝區讀取後可用於讀取的字節數都會發生變化。

輸出:

可供讀取的字節數:4
可供讀取的字節數:3
可供讀取的字節數:2

跳過(長n)

您可以使用skip()方法跳過一定數量的字節而不讀取它們。


public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       input.skip(2);

       while (input.available() != 0) {
           int data = input.read();
           System.out.print(data + ", ");
       }
   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

輸出:

3, 4,

重置()

此方法將緩衝流的位置重置為最後標記的位置。除非設置不同的標記,否則它是位置 0。


public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

       System.out.println("Calling reset() method");
       input.reset();
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

我們將看到調用reset()方法會將我們帶到流的起點。

輸出:

讀取:65
讀取:66
讀取:67
讀取:68
調用 reset() 方法
讀取:65
讀取:66

標記(int readAheadLimit)

ByteArrayInputStream類的mark ()方法在當前字節位置設置內部標記,即緊接在先前讀取的字節之後。此方法採用一個參數,該參數指示在流變為無效之前標記之後可以讀取多少字節。默認情況下,如果未顯式設置標記,則ByteArrayInputStream會標記位置 0 或傳遞給其構造函數的偏移量的位置。重要的是要注意readAheadLimit標記與此類無關。


/* Note: For this class, {@code readAheadLimit}
*  has no meaning.
*
* @since   1.1
*/
public void mark(int readAheadLimit) {
   mark = pos;
}
    

下面是使用mark()reset()方法在ByteArrayInputStream中設置標記的示例。我們將在前面的示例中添加對mark()方法的調用:


public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       input.mark(5);

       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

       System.out.println("Calling reset() method");
       input.reset();

       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

我們可以看到當前流的位置發生了變化。

輸出:

讀取:65
讀取:66
讀取:67
讀取:68
讀取:69
調用 reset() 方法
讀取:68
讀取:69

標記支持()

markSupported ()方法讓您檢查是否可以設置標記。要了解返回值的來源,讓我們轉到方法的代碼:


/**
* Tests if this {@code InputStream} supports mark/reset. The
* {@code markSupported} method of {@code ByteArrayInputStream}
* always returns {@code true}.
*
* @since   1.1
*/
public boolean markSupported() {
   return true;
}
    

該方法始終返回true。讓我們在實踐中對此進行測試。


public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream bais = new ByteArrayInputStream(buf)) {
       boolean isMarkSupported = bais.markSupported();

       System.out.println("isMarkSupported: " + isMarkSupported);
       System.out.println("Read: " + bais.read());
       System.out.println("Read: " + bais.read());

       bais.mark(1);
       System.out.println("Read: " + bais.read());
       isMarkSupported = bais.markSupported();
       System.out.println("isMarkSupported: " + isMarkSupported);

       bais.reset();
       isMarkSupported = bais.markSupported();
       System.out.println("isMarkSupported: " + isMarkSupported);
   } catch (IOException e) {
       e.printStackTrace();
   }
}
    

在執行了mark()reset()方法之後,我們的流總是準備就緒並支持標記:

輸出:

isMarkSupported:true
讀取:65
讀取:66
讀取:67
isMarkSupported:true
isMarkSupported:true

關閉()

為了理解close方法,讓我們也看一下它的內部:


/**
* Closing a {@code ByteArrayInputStream} has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an {@code IOException}.
*/
public void close() throws IOException {
}
    

close 方法的文檔告訴我們關閉 ByteArrayInputStream沒有任何效果。可以在流關閉後調用ByteArrayInputStream類方法而不拋出IOException

我們能得出什麼結論?

當我們想從字節數組中讀取數據時,我們需要一個ByteArrayInputStream 。將此類與知道如何使用InputStreams的其他代碼結合使用而不是單獨使用此類通常是有意義的。