|
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
- Reading and writing data using default behavior of some streams that
is byte by byte read/write causes slow performance.
- Buffered input
streams
and buffered output streams increase performance.
- Custom buffering increases
performance significantly.
|
|