Java I/O Byte Stream Implementation
Byte Stream reads and writes data byte by byte. (Please read Java I/O overview first to understand basic concept of Java I/O).
InputStream and OutputStream are two abstract classes provided by Java that are based on Byte Stream. Let’s go through some of the implementations of InputStream/OutputStream.
FileInputStream/FileOutputStream
Used to read and write contents of a file as a stream of bytes.
// Reading and Writing single byte at a timeFile file = new File("fileTest.txt");
File file1 = new File("fileTest1.txt");
InputStream fis = new FileInputStream(file);
OutputStream fos = new FileOutputStream(file1);//reading file byte by byte and return the byte value of byte read
int data = fis.read();
while(data != -1){ //returns -1 when file ends
System.out.print((char)data);
//writing into file byte by byte
fos.write(data);
data = fis.read();
}
fos.flush();
fos.close();
fis.close();// Reading and writing data into and from byte arrayFile file = new File("fileTest.txt");
byte[] bar = new byte[50]; //note, byte array not char array
String text = "Java is awesome";
OutputStream fos = new FileOutputStream(file);
fos.write(text.getBytes(StandardCharsets.UTF_8));
fos.flush();
fos.close();
InputStream fis = new FileInputStream(file);
fis.read(bar);
for(byte b : bar){
System.out.print((char)b);
}
fis.close();/*Note that we could not always know the max size of bytearray required while reading data from a file to bytearray. So for this we can use Apache common's IOUtils.toByteArray(fileInputStream) to read data from fileInputStream into bytearray. Internally this creates a ByteArrayOutputStream and copies the bytes from FileInputStream to the ByteArrayOutputStream, then calls toByteArray().
e.g. - byte[] bytes = IOUtils.toByteArray(fileInputStream)
*/
Let’s talk about flush() and close(). Some amount of buffering usually occurs when data is written out to a stream, and you never know for sure exactly when the last of the data will actually be sent. Invoking the flush() method guarantees that the last of the data you thought you had already written actually gets out to the file.
File I/O, either reading it or writing uses expensive and limited operating system resources, and so when you’re done, invoking close() will free up those resources.
ByteArrayInputStream/ByteArrayOutputStream
Used to read and write from and to a byte array.
String text = "Awesome Java";
InputStream bis = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
//read() method implementation is same as that of FileInputStream.ByteArrayOutputStream bos = new ByteArrayOutputStream();
//write() method implementation same as that of FileOutputputStream.
byte[] bar = bos.toByteArray();
//obtaining all bytes into a byte array
BufferedInputStream/BufferedOutputStream
This class is used to make lower-level InputStream/OutputStream classes like more efficient and easier to use.
BufferedInputStream read relatively large chunks of data at once and keep this data in a buffer. When you read a byte from the Java BufferedInputStream, it is retrieved from the buffer, which minimizes the number of times that time-intensive read operations are performed.
When the buffer is fully read, the BufferedInputStream reads another larger block of data into the buffer.
Similarly, BufferedOutputStream is used to capture bytes in a buffer, and write the whole buffer in one batch to an underlying OutputStream for increased performance.
Get Lavish Jain’s stories in your inbox
Join Medium for free to get updates from this writer.
Except for adding buffering to your input streams, BufferedInputStream and BufferedOutputStream behaves exactly like an InputStream and OutputStream respectively having same implementations of read() and write() methods.
InputStream bos = new BufferedInputStream(
new FileInputStream("inputFile.txt"));
OutputStream output = new BufferedOutputStream(
new FileOutputStream("outputFile.txt"));//to add custom buffer size
int bufferSize = 8 * 1024;
InputStream bos = new BufferedInputStream(
new FileInputStream("inputFile.txt"),bufferSize);
OutputStream output = new BufferedOutputStream(
new FileOutputStream("outputFile.txt"),bufferSize);
PrintStream
The PrintStream class enables you to write formatted data to an underlying OutptStream. The PrintStream class can format primitive types like int, long etc. formatted as text, rather than as their byte values.
File file = new File("fileTest.txt");
OutputStream fos = new FileOutputStream(file);
PrintStream ps = new PrintStream(fos);//write() method is same as before
ps.write(65);
ps.write("\nHello\n".getBytes(StandardCharsets.UTF_8));//below are some of the extra methods provided by PrintStream
ps.print("Using print\n");
ps.println("Using println");
ps.format("%s is %s %d\n","Java", "Awesome",1);
ps.printf("%s is %s %d","Java", "Awesome",2);
//format and printf have exactly same implementation
ps.flush();
fos.flush();
ps.close();
fos.close();Output (Content printed in the file)-
A
Hello
Using print
Using println
Java is Awesome 1
Java is Awesome 2
System.in/System.out
java.lang.System.in/out are the standard streams provided by Java which are commonly used to provide input to, and output from Java applications.
These are initialized by the Java runtime when a Java VM starts up, so you don’t have to instantiate any streams yourself.
System.in is an InputStream which is connected to keyboard input of console programs. So, if you want to give any input from your keyboard, you’d have to use System.in to read that input. We can read the input using same read() methods provided by InputStream.
System.out is a PrintStream which is used to print something on console. We can use all methods provided by PrintStream with System.out, System.out.println being the most popularly used one.
ObjectInputStream/ObjectOutputStream
These are used in Serialization of Java Objects.
Please read this article on Serialization for examples on ObjectInputStream/ObjectOutputStream.
Bonus — Writing a File into HttpServletResponse
Let us now discuss how to write a file into HttpServletResponse object so that this file get downloaded when API call returns.
@RequestMapping(method = GET, value = "/download")
public void downloadFile(HttpServletResponse response){
File file = new File("/path");
FileInputStream fis = new FileInputStream(file);
byte[] outputBytes = IOUtils.toByteArray(fis);
fis.close();
response.setContentType("plain/csv");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+"\""+"output.csv"+"\"");
OutputStream os = response.getOutputStream();
os.write(outputBytes);
response.flushBuffer();
os.close();}
Here we have written a csv file to HttpServletResponse.
Problem with Byte Streams
As we know now that byte streams read data byte by byte, also it can take more than one byte to represent Unicode characters.
Suppose we have a Unicode character in a file that takes more than one byte (say a Hebrew character ‘ל’)and we are using read() method of FileInputStream that’d read only one byte at a time and if we try to convert each byte into char, in that case we will not get correct data out of file.
File file = new File("fileTest.txt");
OutputStream fos = new FileOutputStream(file);
InputStream fis = new FileInputStream(file);
fos.write("ל".getBytes(StandardCharsets.UTF_8));
int data = fis.read(); //read and return value for first byte only
System.out.println((char)data); // will not print 'ל'
fis.close();
fos.flush();
fos.close();That’s why while reading text we should always use Character Streams.







