Java FileInputStream
Jakob Jenkov |
The Java FileInputStream class, java.io.FileInputStream
, makes it possible to read the contents of a file as
a stream of bytes. The Java FileInputStream
class is a subclass of Java InputStream.
This means that you use the Java FileInputStream
as an InputStream
(FileInputStream
behaves like an InputStream
).
Java FileInputStream Example
Here is a simple FileInputStream
example:
InputStream input = new FileInputStream("c:\\data\\input-text.txt"); int data = input.read(); while(data != -1) { //do something with data... doSomethingWithData(data); data = input.read(); } input.close();
Note: The proper exception handling has been skipped here for the sake of clarity. To learn more about correct exception handling, go to Java IO Exception Handling.
Note also, that since FileInputStream
is a subclass of InputStream
, we can cast
the created FileInputStream
to an InputStream
everywhere we want to, as we do
in the example above.
FileInputStream Constructors
The FileInputStream
class has a three different constructors you can use to create a FileInputStream
instance. I will cover the first two here.
The first constructor takes a String
as parameter. This String
should contain the
path in the file system to where the file to read is located. Here is a code example:
String path = "C:\\user\\data\\thefile.txt"; FileInputStream fileInputStream = new FileInputStream(path);
Notice the path
String
. It needs double backslashes (\\
) to create a single
backslash in the String
, because backslash is an escape character in Java Strings. To get a single
backslash you need to use the escape sequence \\
.
On unix the file path could have looked like this:
String path = "/home/jakobjenkov/data/thefile.txt";
Notice the use of the for-slash (the normal slash character) as directory separator. That is how you write file
paths on unix. Actually, in my experience Java will also understand if you use a /
as directory
separator on Windows (e.g. c:/user/data/thefile.txt
), but don't take my word for it. Test it on your
own system!
The second FileInputStream
constructor takes a File
object as parameter. The File
object has to point to the file you want to read. Here is an example:
String path = "C:\\user\\data\\thefile.txt"; File file = new File(path); FileInputStream fileInputStream = new FileInputStream(file);
Which of the constructors you should use depends on what form you have the path in before opening the FileInputStream
.
If you already have a String
or File
, just use that as it is. There is no particular gain in
converting a String
to a File
, or a File
to a String
first.
read()
The read()
method of a FileInputStream
returns an int
which contains the byte
value of the byte read. If the read()
method returns -1, there is no more data to read in the FileInputStream
,
and it can be closed. That is, -1 as int value, not -1 as byte value. There is a difference here!
You use the read()
method just like the read()
method of an InputStream
.
Here is an example of reading all data in a Java FileInputStream
:
FileInputStream fileInputStream = new FileInputStream("c:\\data\\input-text.txt"); int data = fileInputStream.read(); while(data != -1) { // do something with data variable data = fileInputStream.read(); // read next byte }
When the while
loop terminates, all bytes have been read from the FileInputStream
.
read(byte[])
Being an InputStream
the FileInputStream
also has two read()
methods which
can read data into a byte
array. These methods are inherited from the
Java InputStream class, by the way. These methods are:
int read(byte[])
int read(byte[], int offset, int length)
The first method attempts to fill up the byte
array passed as parameter to it with bytes from
from the FileInputStream
.
The second method attempts to read length
bytes into the byte
array, starting
from cell offset
in the byte
array, and filling forward from there.
Both methods return the number of bytes actually read into the byte
array. In case there are
less bytes to read than what there is space for in the array, or less than you specified in the length
parameter, less bytes will be read into the byte
array. If all bytes have been read from the
FileInputStream
, these read()
methods will return -1
. Therefore it is
necessary to inspect the value returned from these read()
method calls.
Here is an example of calling one of the read(byte[])
methods:
FileInputStream fileInputStream = new FileInputStream("c:\\data\\input-text.txt"); byte[] data = new byte[1024]; int bytesRead = fileInputStream.read(data, 0, data.length); while(bytesRead != -1) { doSomethingWithData(data, bytesRead); bytesRead = fileInputStream.read(data, 0, data.length); }
Notice that read(data, 0, data.length)
is equivalent to read(data)
.
The doSomethingWithData()
method implementation has been left out of this example to keep it short.
But - it represents any set of actions you want to carry out on the read data.
Read Performance
Reading an array of bytes at a time is faster than reading a single byte at a time
from a Java FileInputStream
. 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 a FileInputStream
using a Java BufferedInputStream . The BufferedInputStream
reads a chunk of bytes into a byte array from the underlying FileInputStream
. 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 FileInputStream
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.
Close a FileInputStream
When you are finished reading data from a Java FileInputStream
you must close it.
You close a FileInputStream
by calling the close()
method inherited from InputStream
.
Here is an example of opening a FileInputStream
, reading all data from it, and then closing it:
FileInputStream fileInputStream = new FileInputStream("c:\\data\\input-text.txt"); int data = fileInputStream.read(); while(data != -1) { data = fileInputStream.read(); } fileInputStream.close();
Notice how the while
loop continues until a -1
value is read from the
FileInputStream
read()
method. After that, the while loop exits, and the
FileInputStream
close()
method is called.
The above code is not 100% robust. If an exception is thrown while reading data from the
FileInputStream
, the close()
method is never called. To make the code more robust, you
will have to use the Java 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 FileInputStream
using the try-with-resources construct:
try( FileInputStream fileInputStream = new FileInputStream("file.txt") ) { int data = fileInputStream.read(); while(data != -1){ data = fileInputStream.read(); } }
Notice that the FileInputStream
is declared inside the parentheses after the try
keyword.
This signals to Java that this FileInputStream
is to be managed by the try-with-resources construct.
Once the executing thread exits the try
block, the FileInputStream
is closed.
If an exception is thrown from inside the try
block, the exception is caught, the
FileInputStream
is closed, and then the exception is rethrown. You are thus guaranteed that the
FileInputStream
is closed, when used inside a try-with-resources block.
Convert FileInputStream to Reader
The Java FileInputStream
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 FileInputStream
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 a Java FileInputStream
to an InputStreamReader
:
InputStream inputStream = new FileInputStream("c:\\data\\input.txt"); Reader inputStreamReader = new InputStreamReader(inputStream);
Tweet | |
Jakob Jenkov |