Search this site


 Home  I/O  Buffering  Character streams  NIO intro  Buffers  Channels  Buffer performance

Search this site:
Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

 What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here

Introduction to Java InputStreams

One of the most fundamental components of the java.io package (and indeed of all the Java I/O packages) is the InputStream class. Whether reading from a normal file, network socket, memory or a compressed stream of data, the basic point of call is often some subclass of InputStream.

What is an InputStream?

An InputStream is a reference to source of data (be it a file, network connection etc), that we want to process as follows:

  • we generally want to read the data as "raw bytes" and then write our own code to do something interesting with the bytes;
  • we generally want to read the data in sequential order: that is, to get to the nth byte of data, we have to read all the preceding bytes first, and we're not guaranteed to be able to "jump back" again once we've read them.

We'll see later that if we want to read the bytes as characters, then we can "wrap" the InputStream in a Reader to decode the bytes into characters.

Getting and opening an input stream

Various subclasses of InputStream exist, depending on where we want to read our data from. Here are some examples:

Data sourceType of input stream
(InputStream subclass)
How to obtain
a fileFileInputStreamnew FileInputStream(f)
an entry in a zip fileZipFileInputStream
(Internal class to ZipFile)
new ZipFile(f).getInputStream(entry)
a network socketSocketInputStreamnew Socket(...).getInputStream()
a network source referred to by URLDepends on the protocolnew URL(url).openStream()
a byte arrayByteArrayInputStreamnew ByteArrayInputStream(b)
Example types of InputStream in the standard Java libraries.

Note that in Java there's not really a notion of "opening" an InputStream itself. Once you have constructed an InputStream in one way or another, then it is assumed that the underlying data source (e.g. file) has already been opened if necessary, or that this will happen when you attempt to read the first byte.

On the other hand, we'll see that it is generally important to close the stream once we're done with it. The InputStream class provides the close() method which we need to make sure we call once we're done with the stream. We'll come back to this point in more detail when we consider input stream error handling.

Reading bytes from the stream

Once we have obtained our stream, probably using one of the methods in the table above, then we can call one of the read() methods defined by InputSteam:

ArgumentsActionReturn valueEnd of stream return value
None Read a single byte The next unsigned byte in the file, as an int. -1
a byte array Read bytes from the stream into the array, limited by availability and array size Number of bytes read into the array
a byte array, offset and number of bytes to read Read bytes from the stream into the array, starting at the given offset and limited by availability and number of bytes specified Number of bytes read into the array
Different read() methods provided by InputStream.

So for example, to read consecutive bytes from a file, we can write something as follows:

import java.io.*;

File f = new File(dir, filename);
InputStream in = new FileInputStream(f);
int b;
do {
  b = in.read();
  if (b != -1) {
    System.out.println("The next byte is " + b);
  }
} while (b != -1);
in.close();

In real life, we can write the loop above a bit more succinctly and idiomatically as follows:

int b;
while ((b = in.read()) != -1) {
  ...
}

Notice that although we know that we're dealing specifically with a FileInputStream, we always refer to in simply as an instance of InputStream. It is generally good practice to refer only to the most specific interface or base class that we actually need: our routine will then work as is for any type of input stream. Plus in some cases, for example reading from a zip file entry, we might not actually know (or have any reason to care) what the specific flavour of InputStream actually is.

The code above will get us the bytes out of the file (or other stream) in a very basic way. It does have some problems, however, that we'll need to deal with on the following pages:

  • For the time being, we aren't dealing with error handling: both the read() method and the close() method can throw an IOException (as can the constructor of FileInputStream if the file couldn't be found or read for some reason). We also have the problem that if an I/O error does occur part way through reading, the above code will omit the close() call.
  • It's quite inefficient for any significant number of bytes. For every single byte, we're going to make a separate operating system call. It would be more efficient to make a single OS call to read multiple bytes. An option is to use one of the multi-byte read() calls mentioned above. Sometimes that's not very convenient, however, and we'll see that using the BufferedInputStream wrapper class can be easier.
  • We need to use an extra wrapper class to read character data from the stream instead of "raw" bytes.
comments powered by Disqus

Written by Neil Coffey. Copyright © Javamex UK 2012. All rights reserved.