Precise Java Google
Home  | J2SE  | J2EE  | Book  | Free Books  | Contact
Collections  | StringAndStringBuffer  | Serialization  | IO  | Objects  | Loops  | Exceptions

Performance improvement techniques in I/O

 

This topic illustrates the performance improvement techniques in I/O with the following sections::

Overview of I/O

I/O represents Input and Output streams. We use streams to read from or write to devices such as file or network or console. java.io package provides I/O classes to manipulate streams. This package supports two types of streams - binary streams which handle binary data and character streams which handle character data. InputStream and OutputStream are high level interfaces for manipulating binary streams. Reader and Writer are high level interfaces for manipulating character streams. In this section, the main focus is on binary streams.

The following figure shows the relationship of different IO classes addressed in this section.

 

 

This section examples are tested on Windows millennium, 320mb RAM and JDK 1.3

Note: This section assumes that reader has some basic knowledge of Java I/O.

Optimization with I/O Buffering

By default, most of the streams read or write one byte at a time. This causes poor I/O performance because it takes lot of time to read/write byte by byte when dealing with large amounts of data. I/O provides Buffered streams to override this byte by byte default behaviors. You need to use Buffered streams to buffer the data and then read/write which gives good performance. You need to understand the method's default behavior and act upon that to improve performance.

Suppose if you want to read from or write to a file, FileInputStream facilitates reading from a file and FileOutputStream facilitates writing to a file. These classes have two types of methods, one to read/write one byte at a time and the other method to read/write array of bytes.

FileInputStream.read();

FileInputStream.read(byte[] b);

FileInputStream.read(byte[] b, int off, int length);

FileOutputStream.write(int b);

FileOutputStream.write(byte[] b);

FileOutputStream.writebyte[] b, int off, int length);

We have buffered streams to buffer data and to improve performance, they are BufferedInputStream and BufferedOutputStream. The constructor takes other stream as parameter, here it is FileInputStream or FileOutputStream. They have two methods :

BufferedInputStream.read();

BufferedInputStream.read(byte[] b, int off, int len);

BufferedOutputStream.write(int b);

BufferedOutputStream.write(byte[] b, int off, int len);

The following figure shows how buffered streams divert the data flow

 

 

The default size for buffer streams is 512 bytes. It accumulates the data till it reaches this capacity and reads from/ writes to destination. You can change this default size by passing required buffer size through constructor that is

BufferedInputStream(InputStream in, int size);

BufferedOutputStream(OutputStream out, int size);

The following IOTest.java shows the bench mark differences between normal streams, buffered streams and custom buffering. Bench marks clearly show buffered streams improve performance significantly than normal streams. and It also shows that custom buffering gives even better results than buffered streams.

Optimization with Custom Buffering

Custom Buffering means creating your own buffer while reading or writing streams using existing methods. Some of the methods in streams take byte array as parameter. They read/ write byte array at a time instead of read/write byte by byte. The following methods come under that category.

FileInputStream.read(byte[] b);

FileInputStream.read(byte[] b, int off, int length);

FileOutputStream.write(byte[] b);

FileOutputStream.write(byte[] b, int off, int length);

Using these methods you can increase performance significantly.

IOTest.java shows the bench marks for all of the above alternatives. It reads 28KB size file and writes into another file.

IOTest.java

package com.performance.io;

// This class shows the different bench marks using default behavior, buffered streams and custom buffering 

import java.io.*;

public class IOTest {

public static void main(String[] args){

             IOTest io = new IOTest();

             try{

             long startTime = System.currentTimeMillis();

             io.readWrite("c:/temp/Bookmarks.html","c:/temp/Bookmarks1.html");    

             long endTime = System.currentTimeMillis();

             System.out.println("Time taken for reading and writing using default behaviour : "

                                                           + (endTime - startTime) + " milli seconds" );

 

             long startTime1 = System.currentTimeMillis();

             io.readWriteBuffer("c:/temp/Bookmarks.html","c:/temp/Bookmarks2.html");           

             long endTime1 = System.currentTimeMillis();

             System.out.println("Time taken for reading and writing using buffered streams : "

                                                           + (endTime1 - startTime1) + " milli seconds" );

 

             long startTime2 = System.currentTimeMillis();

             io.readWriteArray("c:/temp/Bookmarks.html","c:/temp/Bookmarks3.html");             

             long endTime2 = System.currentTimeMillis();

             System.out.println("Time taken for reading and writing using custom buffering : "

                                                           + (endTime2 - startTime2) + " milli seconds" );

             }catch(IOException e){ e.printStackTrace();}

}

public static void readWrite(String fileFrom, String fileTo) throws IOException{

             InputStream in = null;

             OutputStream out = null;

             try{

                          in = new FileInputStream(fileFrom);

                          out = new FileOutputStream(fileTo);

                          while(true){

                                          int bytedata = in.read();

                                          if(bytedata == -1)

                                          break;

                                          out.write(bytedata);

                          }

             }

             finally{

              if(in != null)

                          in.close();

              if(out !=null)

                          out.close();

             }

}

public static void readWriteBuffer(String fileFrom, String fileTo) throws IOException{

             InputStream inBuffer = null;

             OutputStream outBuffer = null;

             try{

                          InputStream in = new FileInputStream(fileFrom);

                          inBuffer = new BufferedInputStream(in);

                          OutputStream out = new FileOutputStream(fileTo);

                          outBuffer = new BufferedOutputStream(out);

                          while(true){

                                          int bytedata = inBuffer.read();

                                          if(bytedata == -1)

                                          break;

                                          out.write(bytedata);

                          }

             }

             finally{

              if(inBuffer != null)

                          inBuffer.close();

              if(outBuffer !=null)

                          outBuffer.close();

             }

}          

public static void readWriteArray(String fileFrom, String fileTo) throws IOException{

             InputStream in = null;

             OutputStream out = null;

             try{

                          in = new FileInputStream(fileFrom);

                          out = new FileOutputStream(fileTo);

                          int availableLength = in.available();

                          byte[] totalBytes = new byte[availableLength];

                          int bytedata = in.read(totalBytes);

                          out.write(totalBytes);

                            

             }

             finally{

              if(in != null)

                          in.close();

              if(out !=null)

                          out.close();

             }

}          

}

The output of this code is

   Time taken for reading and writing using default behavior : 660 milli seconds

Time taken for reading and writing using buffered streams : 270 milli seconds

Time taken for reading and writing using custom buffering : 0 milli seconds

 

These bench marks clearly show that buffered streams  give better performance and custom buffering gives best performance. Note that custom buffering takes lot of memory if your file size is large, you should be careful about the memory capability of your system. If custom buffering takes lot of memory, try to reduce the array size so that the memory usage will not be large.

 

Key Points

  1. Reading and writing data using default behavior of some streams that is byte by byte  read/write causes slow performance.
  2. Buffered input streams and buffered output streams increase performance.
  3. Custom buffering increases performance significantly.

 

Feed back

We appreciate and welcome your comments on this section. Email commentsZZZ@precisejavaZZZ.com (remove ZZZ which is placed to prevent spam). Please note that we may not be able to reply to all the emails due to huge number of emails that we receive but we appreciate your comments and feedback.

 





Copyright © 2001-2005, Ravi Kalidindi and Rohini Kalidindi. All rights reserved.