Java IO
-
Java IO Tutorial
-
Java IO Overview
-
Java IO: Files
-
Java IO: Streams
-
Java IO: Pipes
-
Java IO: Networking
-
Java IO: Byte & Char Arrays
-
Java System.in, System.out, and System.error
-
Java IO: Input Parsing
-
Java IO: Readers and Writers
-
Java IO: Concurrent IO
-
Java IO: Exception Handling
-
Java InputStream
-
Java OutputStream
-
Java FileInputStream
-
Java FileOutputStream
-
Java RandomAccessFile
-
Java File
-
Java IO: PipedInputStream
-
Java IO: PipedOutputStream
-
Java ByteArrayInputStream
-
Java ByteArrayOutputStream
-
Java IO: FilterInputStream
-
Java IO: FilterOutputStream
-
Java BufferedInputStream
-
Java BufferedOutputStream
-
Java PushbackInputStream
-
Java IO: SequenceInputStream
-
Java DataInputStream
-
Java IO: DataOutputStream
-
Java IO: PrintStream
-
Java IO: ObjectInputStream
-
Java IO: ObjectOutputStream
-
Java IO: Serializable
-
Java Reader
-
Java Writer
-
Java InputStreamReader
-
Java OutputStreamWriter
-
Java FileReader
-
Java FileWriter
-
Java IO: PipedReader
-
Java IO: PipedWriter
-
Java IO: CharArrayReader
-
Java IO: CharArrayWriter
-
Java BufferedReader
-
Java BufferedWriter
-
Java IO: FilterReader
-
Java IO: FilterWriter
-
Java PushbackReader
-
Java IO: LineNumberReader
-
Java StreamTokenizer
-
Java IO: PrintWriter
-
Java IO: StringReader
-
Java IO: StringWriter
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.
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:
ByteArrayInputStream
FileInputStream
PipedInputStream
BufferedInputStream
FilterInputStream
PushbackInputStream
DataInputStream
ObjectInputStream
SequenceInputStream
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).
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
.
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.
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();
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.
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.
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.
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.
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);