The ByteArrayInputStream class in the java.io package can be used to read an input array (of bytes).

To create a byte array input stream, we must first import the java.io.ByteArrayInputStream package. After we import the package, we have two constructors available for creating an input stream:


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

There are 4 fields inside the class:


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

And here are our constructors:


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

Methods of the ByteArrayInputStream class

Method Action
int read() Reads the next byte of data from this input stream.
int read(byte b[], int off, int len) Reads several bytes from the input stream and stores them in buffer array b.
off is an offset into target array b.
len is the maximum number of bytes to read.
long skip(long n) Skips n bytes of input from this input stream. Returns the number of bytes skipped (it may be less than n if we reach the end of the input stream).
int available() Returns the number of remaining bytes that can be read (or skipped) from this input stream.
void reset() Resets the buffer to the marked position. The marked position is 0 unless another position is marked or a different offset is specified in the constructor.
boolean markSupported() Checks whether this InputStream supports marking/resetting. Returns true for ByteArrayInputStream.
void close() Doesn't do anything.
void mark(int readAheadLimit) Sets the mark field equal to the current position. If the reset method is called, then subsequent reading will start from that position. The readAheadLimit parameter is not used and does not affect the behavior of the method.

Let's take a closer look at these methods and see how they work in practice.

read()

When you want to read bytes from a ByteArrayInputStream just like you would from an ordinary InputStream, you can use the read() method.


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()

If you want to check whether there is something in your buffer, you can call the available() method.


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();
   }
}
    

We will see that the number of bytes available for reading changes after each read from the buffer.

Output:

Bytes available for reading: 4
Bytes available for reading: 3
Bytes available for reading: 2

skip(long n)

You can use the skip() method to skip a certain number of bytes and not read them.


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();
   }
}
    

Output:

3, 4,

reset()

This method resets the buffered stream's position to the last marked position. It is position 0 unless a different mark is set.


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();
   }
}
    

We will see that calling the reset() method takes us to our stream's starting point.

Output:

Read: 65
Read: 66
Read: 67
Read: 68
Calling reset() method
Read: 65
Read: 66

mark(int readAheadLimit)

The mark() method of the ByteArrayInputStream class sets the internal mark at the current byte position, that is, immediately after the previously read byte. This method takes a parameter that indicates how many bytes can be read after the mark before it stream becomes invalid. By default, if the mark is not set explicitly, a ByteArrayInputStream marks position 0 or the position of the offset passed to its constructor. It is important to note that the readAheadLimit mark is irrelevant for this class.


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

Here is an example of setting a mark in a ByteArrayInputStream using its mark() and reset() methods. We will add a call to the mark() method to the previous example:


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();
   }
}
    

We can see that the current stream's position has changed.

Output:

Read: 65
Read: 66
Read: 67
Read: 68
Read: 69
Calling reset() method
Read: 68
Read: 69

markSupported()

The markSupported() method lets you check whether a mark can be set. To understand where the return value comes from, let's go to the code of the method:


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

The method always returns true. Let's test this in practice.


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();
   }
}
    

After executing the mark() and reset() methods, our stream is always ready and supports marks:

Output:

isMarkSupported: true
Read: 65
Read: 66
Read: 67
isMarkSupported: true
isMarkSupported: true

close()

And to understand the close method, let's also take a peek inside it:


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

The documentation for the close method tells us that closing a ByteArrayInputStream has no effect. The ByteArrayInputStream class methods can be called after the stream is closed without throwing an IOException.

What can we conclude?

We need a ByteArrayInputStream when we want to read data from a byte array. It usually makes sense to use this class in combination with other code that knows how to work with InputStreams rather than by itself.