java.ioパッケージの ByteArrayInputStream クラスを使用し、(バイトの) 入力配列を読み取ることができます。

バイト配列入力ストリームを作成するには、まずjava.io.ByteArrayInputStreamパッケージをインポートする必要があります。パッケージをインポートすると、入力ストリームの作成に使用できる 2 つのコンストラクターが用意されます。


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() この入力ストリームからデータの次のバイトを読み取ります。
int read(byte b[], int off, int len) 入力ストリームから数バイトを読み取り、バッファ配列bに格納します。
off はターゲット配列bへのオフセットです。
lenは読み取る最大バイト数です。
ロングスキップ(ロングn) この入力ストリームからの入力を n バイトスキップします。スキップされたバイト数を返します (入力ストリームの最後に到達すると、バイト数が n 未満になる可能性があります)。
int 利用可能() この入力ストリームから読み取る (またはスキップする) ことができる残りのバイト数を返します。
ボイドリセット() バッファをマークされた位置にリセットします。別の位置がマークされるか、コンストラクターで異なるオフセットが指定されない限り、マークされた位置は 0 です。
ブールマークサポート済み() このInputStreamがマーキング/リセットをサポートしているかどうかを確認します。ByteArrayInputStreamの場合はtrueを返します
ボイドクローズ() 何もしません。
void マーク(int readAheadLimit) を設定しますマーク現在の位置と等しいフィールド。リセットメソッドが呼び出されると、その後の読み取りはその位置から開始されます。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();
   }
}
    

replace()メソッドを呼び出すと、ストリームの開始点に移動することがわかります。

出力:

読み取り: 65
読み取り: 66
読み取り: 67
読み取り: 68
replace() メソッドの呼び出し
読み取り: 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
replace() メソッドの呼び出し
読み取り: 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の操作方法を知っている他のコードと組み合わせて使用​​することが合理的です。