Java InputStream

The Java InputStream class, java.io.InputStream, represents an ordered stream of bytes. In other words, you can read data
from a Java InputStream as an ordered sequence of bytes. This is useful when reading data from a file,
or received over the network.

InputStream Subclasses

The Java InputStream class is the base class (superclass) of all input streams in the Java IO API.
Each subclass of InputStream typically has a very specific use, but can be used as an InputStream.
The InputStream subclasses are:

InputStreams and Sources

A Java InputStream is typically connected to some data source, like a file, network connection,
pipe etc. This is also explained in more detail in the Java IO Overview text.

Java InputStream Example

Java InputStream‘s are used for reading byte based data, one byte at a time. Here is a Java InputStream example
which reads all the bytes from a file:

InputStream inputstream = new FileInputStream("c:\\data\\input-text.txt");

int data = inputstream.read();
while(data != -1) {
  //do something with data...
  doSomethingWithData(data);

  data = inputstream.read();
}
inputstream.close();

This example creates a new FileInputStream instance. FileInputStream is a subclass of
InputStream so it is safe to assign an instance of FileInputStream to an InputStream
variable (the inputstream variable).

read()

The read() method of an InputStream returns an int which contains the byte value of the
byte read. Here is an InputStream read() example:

int data = inputstream.read();

To read all bytes in a Java InputStream you must keep reading until the value -1 is
returned. This value means that there are no more bytes to read from the InputStream. Here is
an example of reading all bytes from a Java InputStream :

int data = inputStream.read();
while(data != -1) {
    // do something with data variable

    data = inputStream.read(); // read next byte
}

Subclasses of InputStream may have alternative read() methods. For instance, the
DataInputStream allows you to read Java primitives like int, long, float, double, boolean etc.
with its corresponding methods readBoolean(), readDouble() etc.

End of Stream

If the read() method returns -1, the end of stream has been reached, meaning there is no more data to read in the InputStream. That is, -1 as int value, not -1 as byte or short value. There is a difference here!

When the end of stream has been reached, you can close the InputStream.

read(byte[])

The InputStream class also contains two read() methods which can read data from the
InputStream‘s source into a byte array. These methods are:

  • int read(byte[])
  • int read(byte[], int offset, int length)

The read(byte[]) method will attempt to read as many bytes into the byte array given as parameter
as the array has space for. The read(byte[]) method returns an int telling how many
bytes were actually read. In case less bytes could be read from the InputStream than the byte
array has space for, the rest of the byte array will contain the same data as it did before the read
started. Remember to inspect the returned int to see how many bytes were actually read into the byte
array.

The read(byte[], int offset, int length) method also reads bytes into a byte array,
but starts at offset bytes into the array, and reads a maximum of length bytes into
the array from that position. Again, the read(byte[], int offset, int length) method returns
an int telling how many bytes were actually read into the array, so remember to check this value
before processing the read bytes.

For both methods, if the end of stream has been reached, the method returns -1 as the number of bytes read.

Here is an example of how it could look to use the InputStream‘s read(byte[]) method:

InputStream inputstream = new FileInputStream("c:\\data\\input-text.txt");

byte[] data      = new byte[1024];
int    bytesRead = inputstream.read(data);

while(bytesRead != -1) {
  doSomethingWithData(data, bytesRead);

  bytesRead = inputstream.read(data);
}
inputstream.close();

First this example create a byte array. Then it creates an int variable named
bytesRead to hold the number of bytes read for each read(byte[]) call, and
immediately assigns bytesRead the value returned from the first read(byte[]) call.

Inside the while loop the doSomethingWithData() method is called, passing along
the data byte array as well as how many bytes were read into the array as parameters.
At the end of the while loop data is read into the byte array again.

It should not take much imagination to figure out how to use the read(byte[], int offset, int length)
method instead of read(byte[]). You pretty much just replace the read(byte[]) calls
with read(byte[], int offset, int length) calls.

readAllBytes()

The Java InputStream class contains a method called readAllBytes() (since Java 9).
This method reads all the bytes available in the InputStream and returns a single byte array with the bytes in.
This method is useful if you need to read all bytes from a file via a
FileInputStream into a byte array.
Here is an example of reading all bytes from a Java InputStream via readAllBytes():

byte[] fileBytes = null;
try(InputStream input = new FileInputStream("myfile.txt")) {
   fileBytes = input.readALlBytes();
}

Read Performance

Reading an array of bytes at a time is faster than reading a single byte at a time
from a Java InputStream. The difference can easily be a factor 10 or more in performance increase, by
reading an array of bytes rather than reading a single byte at a time.

The exact speedup gained depends on the size of the byte array you read, and the OS, hardware etc. of the
computer you are running the code on. You should study the hard disk buffer sizes etc. of the target system
before deciding. However buffer sizes of 8KB and up will give a good speedup. However, once your byte array
exceeds the capacity of the underlying OS and hardware, you won’t get a bigger speedup from a bigger byte array.

You will probably have to experiment with different byte array size and measure read performance, to find
the optimal byte array size.

Transparent Buffering via BufferedInputStream

You can add transparent, automatic reading and buffering of an array of bytes from an InputStream
using a Java BufferedInputStream . The BufferedInputStream
reads a chunk of bytes into a byte array from the underlying InputStream. You can then read
the bytes one by one from the BufferedInputStream and still get a lot of the speedup that comes
from reading an array of bytes rather than one byte at a time. Here is an example of wrapping a
Java InputStream in a BufferedInputStream :

InputStream input = new BufferedInputStream(
                      new FileInputStream("c:\\data\\input-file.txt"),
                        1024 * 1024        /* buffer size */
    );

Notice, that a BufferedInputStream is an InputStream subclass and can be used
in any place where an InputStream can be used.

mark() and reset()

The InputStream class has two methods called mark() and reset() which
subclasses of InputStream may or may not support.

If an InputStream subclass supports the mark() and reset() methods, then
that subclass should override the markSupported() to return true. If the markSupported()
method returns false then mark() and reset() are not supported.

The mark() sets a mark internally in the InputStream which marks the point in the
stream to which data has been read so far. The code using the InputStream can then continue reading
data from it. If the code using the InputStream wants to go back to the point in the stream where
the mark was set, the code calls reset() on the InputStream. The InputStream
then “rewinds” and go back to the mark, and start returning (reading) data from that point again. This will of
course result in some data being returned more than once from the InputStream.

The methods mark() and reset() methods are typically used when implementing parsers.
Sometimes a parser may need to read ahead in the InputStream and if the parser doesn’t find what it
expected, it may need to rewind back and try to match the read data against something else.

Closing an InputStream

When you are done with a Java InputStream you must close it. You close an InputStream
by calling the InputStream close() method. Here is an example of opening an
InputStream, reading all data from it, and then closing it:

InputStream inputstream = new FileInputStream("c:\\data\\input-text.txt");

int data = inputstream.read();
while(data != -1) {
  data = inputstream.read();
}
inputstream.close();

Notice how the while loop continues until a -1 value is read from the
InputStream read() method. After that, the while loop exits, and the
InputStream close() method is called.

The above code is not 100% robust. If an exception is thrown while reading data from the
InputStream, the close() method is never called. To make the code more robust, you
will have to use the Java try-with-resources construct.
Proper exception handling for use of Java IO classes is also explained in my tutorial on
Java IO Exception Handling.

Here is an example of closing a Java InputStream using the try-with-resources construct:

try( InputStream inputstream = new FileInputStream("file.txt") ) {

    int data = inputstream.read();
    while(data != -1){
        data = inputstream.read();
    }
}

Notice how the InputStream is now declared inside the parentheses after the try keyword.
This signals to Java that this InputStream is to be managed by the try-with-resources construct.

Once the executing thread exits the try block, the inputstream variable is closed.
If an exception is thrown from inside the try block, the exception is caught, the
InputStream is closed, and then the exception is rethrown. You are thus guaranteed that the
InputStream is closed, when used inside a try-with-resources block.

Convert InputStream to Reader

The Java InputStream is a byte based stream of data. As you may know, the Java IO API also
has a character based set of input streams called “Readers”. You can convert a Java InputStream
to a Java Reader using the Java InputStreamReader.
You can read more about how to use the InputStreamReader by clicking the link in the previous
sentence, but here is a quick example of converting an InputStream to an InputStreamReader:

InputStream inputStream       = new FileInputStream("c:\\data\\input.txt");
Reader      inputStreamReader = new InputStreamReader(inputStream);