Progress bars provide visual feedback on the progress of lengthy tasks, such as reading a stream of bytes stored in a file. In some cases, Java progress monitors cannot be used because the number of bytes that remain to be read is not available from the
InputStream object that the bytes are read from. This article introduces the
SizeInputStream class that enables reading progress to be monitored when the number of bytes to be read can be determined from sources other than an
InputStream object, such as from a
Interactive applications should provide the user with feedback on the progress of lengthy tasks with a progress bar. As the task progresses, the length of the bar increases from left to right to indicate how much of the task has been completed and to enable users to estimate how much longer it will take to complete:
A typical example of the need for a progress bar is when reading a stream of bytes, such as the contents of a large file. The Java
InputStream class provides a generic interface for reading bytes from a variety of sources. Classes for reading bytes from files, pipes, and filters, for example, are implemented by sub-classing
InputStream. As well as providing methods to read one or more bytes from a stream, the
InputStream class also provides an
int available()method that returns the number of bytes that remain to be read from the stream.
Java also provides a
ProgressMonitorInputStream class that reads bytes from an
InputStream object and pops up a progress bar if reading the stream will take more than a specified minimum amount of time (Geary 1999, p. 281). The
ProgressMonitorInputStream class uses the
available() method of class
InputStream to determine how many bytes remain to be read from the stream. The length of the bar is calculated by subtracting the initial number of bytes that were available to read from the stream from the number of bytes that are left to read.
Some input stream classes, such as the
ZipInputStream class for reading bytes from files compressed in the Zip format, cannot know in advance how many bytes are available to read (see for example Java Bug Parade 4028605 and 4186776). In such cases, the
available() method will always return 1 which makes it impossible to monitor the progress of reading from such streams.
In some cases client code can determine the number of bytes to be read from an input stream other than by calling the
available() method. For example, if the bytes to be read can be accessed with a URL, the number of bytes can be determined by calling the
getContentLength() method of a
URLConnection object. The following Java code determines the number of bytes in a resource that is accessed with a URL.
When the number of bytes to be read can be determined, the
SizeInputStream class can be used to overcome the inability of an
available() method to return a useful byte count. The
SizeInputStream class wraps an
InputStream object and the number of bytes that can be read from it, as determined, for example, by using a
URLConnection object. The
available() method of a
SizeInputStream object always returns the correct number of bytes that remain to be read. By monitoring the progress of reading from a
SizeInputStream object, a
ProgressMonitorInputStream object can monitor the progress of reading from an
InputStream object, even if it’s
available() method does not return a useful byte count.
SizeInputStream object is constructed with an
InputStream to read bytes from, and the number of bytes that are available to read. The three methods to read bytes from a
read(byte b), and
read(byte b, int off, int len), read the requested number of bytes from the enclosed
InputStream and record the number of bytes read. The
available() returns the number of bytes left to read from the
InputStream by subtracting the number of bytes that have been read from the number of bytes passed to the constructor.
The following Java code creates a
ProgressMonitorInputStream with a
SizeInputStream object, which provides the stream to read from and determines the number of bytes to read.
The implementation of the
SizeInputStream class is shown below.