CodeGym/Java Blog/Java IO & NIO/Input/output in Java. FileInputStream, FileOutputStream, ...
Author
Alex Vypirailenko
Java Developer at Toshiba Global Commerce Solutions

Input/output in Java. FileInputStream, FileOutputStream, and BufferedInputStream classes

Published in the Java IO & NIO group
members
"Hi! In today's lesson, we'll continue our conversation about input and output streams in Java (Java I/O). This is not the first lesson on this topic, and it certainly won't be the last :) Input/output in Java. FileInputStream, FileOutputStream, and BufferedInputStream classes - 1As it happens, the Java language provides many ways to work with I/O. There are quite a few classes that implement this functionality, so we've divided them into several lessons — so you won't get confused from the start :) In past lessons, we touched on BufferedReader, as well as the InputStream and OutputStream abstract classes and several descendants. Today we'll consider 3 new classes: FileInputStream,  FileOutputStream, and BufferedInputStream.

The FileOutputStream class

The main purpose of the FileOutputStream class is to write bytes to a file. Nothing complicated :) FileOutputStream is one of the implementations of the OutputStream abstract class. In the constructor, objects of this class take either the path to the target file (where the bytes should be written) or a File object. We'll examine examples of each:
public class Main {

   public static void main(String[] args) throws IOException {

       File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
       FileOutputStream fileOutputStream = new FileOutputStream(file);

       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";

       fileOutputStream.write(greetings.getBytes());
       fileOutputStream.close();
   }
}
When creating the File object, we passed the desired path to the constructor. We don't need to create it in advance: if it doesn't exist, the program will create it. You can also get by without creating an extra object, simply passing a string with the path:
public class Main {

    public static void main(String[] args) throws IOException {

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";

       fileOutputStream.write(greetings.getBytes());
       fileOutputStream.close();
   }
}
The result in both cases will be the same. We can open our file and see the following there:

Hi! Welcome to CodeGym — The best site for would-be programmers!
But there's one nuance here. Try running the code from the example above several times in a row. Then look in the file and answer this question: how many lines does it have? Just one. But you ran the code several times. It turns out that the data is overwritten every time — the old is replaced by the new. What do we do if that doesn't suit us and we need to write sequentially to the file? What if we want to write our greeting to a file three times in a row? It's all very simple. Since the language can't know what behavior we need in each case, the FileOutputStream contrucutor can take an additional parameter — boolean append. If its value is true, the data will be written to the end of the file. If it is false (and by default it is false), any old data will be erased and replaced by new data. Let's check this by running our modified code three times:
public class Main {

   public static void main(String[] args) throws IOException {

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";

       fileOutputStream.write(greetings.getBytes());
       fileOutputStream.close();
   }
}
File contents:

Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers!
Now that's different! Don't forget about this feature when using I/O classes. There was a time when I spent hours on tasks, racking my brains for hours, trying to understand how my data was disappearing from files :) And of course, just as with other I/O classes, don't forget to use the close() method to free resources.

The FileInputStream class

The FileInputStream has the opposite purpose — reading bytes from a file. Just as FileOutputStream inherits OutputStream, this class derives from the InputStream abstract class. We'll write a few lines of text in our "test.txt" file:

"So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters"
Input/output in Java. FileInputStream, FileOutputStream, and BufferedInputStream classes - 2Here what it looks like to read data from a file using FileInputStream:
public class Main {

   public static void main(String[] args) throws IOException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");

       int i;

       while((i=fileInputStream.read())!= -1){

           System.out.print((char)i);

       }
   }
}
We read one byte from the file, convert the read bytes into characters and display them on the console. And here's the console output:

So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters

The BufferedInputStream class

I think, given the knowledge from past lessons, you can easily say why we need the BufferedInputStream class and what advantages it has compared to FileInputStream :) We've already encountered buffered streams, so try to guess (or remember) before you continue reading :) Buffered streams are needed mainly to optimize I/O. Accessing a data source, such as reading from a file, is an expensive operation in terms of performance And to access a file to read each byte is wasteful. That's why BufferedInputStream reads data not one byte at a time, but in blocks, and temporarily stores them in a special buffer. This lets us optimize the program by reducing the number of times we access the file. Let's see what this looks like:
public class Main {

   public static void main(String[] args) throws IOException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);

       int i;

       while((i = bufferedInputStream.read())!= -1){

           System.out.print((char)i);
       }
   }
}
Here we created a BufferedInputStream object. Its constructor takes an instance of the InputStream class or any of its descendants, so FileInputStream will do. As an additional argument, it takes the buffer size in bytes. Thanks to this argument, the data will now be read from the file not one byte at a time, but 200 bytes at a time! Imagine how much we've reduced the number of file accesses. To compare performance, you can take a large text file (several megabytes of text) and compare how long it takes in milliseconds to read and output to the console using FileInputStream and BufferedInputStream. Here's code that demonstrates both options:
public class Main {

   public static void main(String[] args) throws IOException {

       Date date = new Date();

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

       int i;
       while((i = bufferedInputStream.read())!= -1){

           System.out.print((char)i);
       }

       Date date1 = new Date();
       System.out.println((date1.getTime() - date.getTime()));
   }
}


public class Main {

   public static void main(String[] args) throws IOException {

       Date date = new Date();
       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");

       int i;
       while((i = fileInputStream.read())!= -1){

           System.out.print((char)i);
       }


       Date date1 = new Date();
       System.out.println((date1.getTime() - date.getTime()));
   }
}
When reading a 1.5 MB file on my computer, FileInputStream completed the work in ~3500 milliseconds, but BufferedInputStream managed it in ~1700 milliseconds. As you can see, the buffered stream optimized the work, cutting it in half! :) We will continue to study I/O classes — see you soon!
Comments (17)
  • Popular
  • New
  • Old
You must be signed in to leave a comment
Dmytro Panshyn
Level 25 , Poland, Poland
24 November 2023, 11:07
Good article!
Korlat
Level 25 , Gasteiz, Basque Country, Spain
6 July 2022, 16:50
while((i=fileInputStream.read())!= -1){ System.out.print((char)i); } Why -1 ???
Matthestub
Level 27 , Warsaw, Poland
7 July 2022, 10:03
If no byte is available in the file passed to the fileInputStream then the "reading stream" is at the end of the file and read() method will return -1. read() method reads bytes and converts them to int value, but the scope of values on witch it operates is from -1 to 255, so the while() loop will work until every byte from file is read.
Hoa Nguyen
Level 15 , Australia
Expert
17 February 2022, 05:44
Excellent lesson! Very detailed! Very clear! Thank you! P/S: the more I learn from you, the more I find my university course on structured programming (using Java) a waste of money. But more importantly, the lack of clear explanation has made many students think that they are not capable of programming which is not true. The bad teaching cuts the dreams of many students short. And that cannot be measured by money.
Gellert Varga
Level 23 , Szekesfehervar, Hungary
2 July 2021, 22:39
To use BufferedInputStream does not only halve the time, but reduces it by a much larger amount. The two programs above that compare the speed of the two streams unfortunately add the slowness of the print() method to the measurement, and thus greatly distorts the final result. Let's remove the print((char)i) method from the loop so that we can really only measure the speed of the read() methods. I read a 2.5MB (2.5 million bytes) file this way, and the result is: With FileInputStream: ~3100 ms, With BufferedInputStream: 110 ms. 30 times difference!
Aakankasha Sharma
Level 18 , Chandigarh, India
15 May 2021, 02:50
while((i=fileInputStream.read())!= -1){ System.out.print((char)i); } read() returns only one byte, and we are trying to print a char. How is it printing the char properly, shouldn't it print a byte?
Sansho
Level 19 , Bordeaux, France
25 June 2021, 09:07
When you cast a byte to a char, you ask your program to pick the char in the ASCIITable at index[byte] (ie: at index 1 you get: ☺ (you can do ALT + number) )
Gellert Varga
Level 23 , Szekesfehervar, Hungary
30 June 2021, 22:22
At index 1 of the ASCII code table (and between 0 and 31 too) there are so-called control characters, not a smile:) ALT key commands do not match the ASCII code table exactly. http://www.asciitable.com/ And converting bytes to char in singles will not always give good results.This only works if you only read the simplest characters that are in the ASCII code table. In this simplest case, a single byte can represent a complete character, but in many cases several bytes need to be scanned to get one complete character. For example, the most common character encoding is UTF-8. In this encoding, variable number of bytes can represent one piece of character: - basic characters are transmitted in 1 byte (characters of the ASCII-table). - in case of other characters it often uses 2 bytes to represent a character, - but the UTF-8 is able to encode any of the 65536 Unicode base characters in maximum 3 bytes. If 2 or 3 bytes represent one character, and you convert them byte by byte to char, the result will be a mess like when you narrowed a large value long to short, for example.
Karas Java Developer
6 April 2021, 18:01
"So close no matter how far Couldn't be much more from the heart Forever trusting who we are And nothing else matters" Sounds familiar somehow.... is it a poem? LOL!
Dominik
Level 19 , Katowice, Poland
17 June 2021, 17:26
Poem by Codellica 🤘
Bodea Tudor Andrei
Level 25 , Cluj-Napoca, Romania
15 January 2021, 07:37
At the start of the FIleInputStream where it says "We read one byte from the file, convert the read bytes into files and display them on the console." shouldn't it be "convert the read bytes intro chars" ?
Andrei
Level 41
18 January 2021, 09:50
It seems like an error, yes.
Gellert Varga
Level 23 , Szekesfehervar, Hungary
3 July 2021, 16:06
In this case, we just need to tell it the CG staff and they will fix it. They have already fixed it.:)
Collin M
Level 22 , Germiston, South Africa
2 October 2020, 17:17
Very good article, it has cleared some confusions I had with Java I/O
Ntuthuko Xaba
Level 18 , Johannesburg, South Africa
20 May 2020, 16:16
For some reason all these examples don't seem to work in my IDE.I tried using a different filepath but got exceptions. Anyone else experiencing the same problem?
Peter Gray
Level 20 , Compiegne, France
1 June 2020, 21:52
Are you sure you've importer or needed packages? What's the message in the console saying?
Ahmad
Level 23 , Riyadh, Saudi Arabia
5 May 2020, 12:21
very simple and nice article