Performance gain of using NIO channels as opposed to regular streams for doing file I/O

To test things out, I wrote a couple small Java programs to copy a file:

CopyFile1.java: uses the old approach using BufferedInput/BufferedOutputStreams with the default buffer size of 2048 bytes
CopyFile2.java: uses the NIO libraries with different buffer sizes
CopyFile3.java: uses the NIO FileChannel method transferTo

CopyFile1.java uses BufferedInputStream and BufferedOutputStream. If you look at the source code for these files, the default buffer is an array of 2048 bytes. The first version of the NIO CopyFile2 program is also set to use an internal buffer of 2048 bytes. Other tests have been done with larger buffer sizes. As expected, the more buffer space allocated, the higher the performance (at a cost of more memory usage).

The result of copying the Java SDK file j2sdk-1_4_0-win.exe(37Meg) using JDK1.2.2, JDK1.3 and JDK1.4 on a Win2000/450Mhz machine is plotted here:


(All numbers are seconds)

CopyFile1.java:

import java.io.*;
 
public class CopyFile1
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile1 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
 
      int k;
      while ((k = bis.read()) != -1) {
         bos.write(k);
      }
   
      bis.close();
      bos.close();
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile2.java:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;
 
public class CopyFile2
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile2 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);
      FileOutputStream fos = new FileOutputStream(dest);
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      ByteBuffer buffer = ByteBuffer.allocateDirect(2048); 
 
      int n = channelIn.read(buffer);
      while (n > -1) {
         buffer.flip();
         channelOut.write(buffer);
         buffer.clear();
  
         n = channelIn.read(buffer);
      }      
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile3.java:

import java.nio.*;    
import java.nio.channels.*;    
import java.io.*;        
 
public class CopyFile3 
{        
   public static void main(String args[]) throws IOException {                
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile3 source dest");
         System.exit(1);
      }             
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);            
      FileOutputStream fos = new FileOutputStream(dest);            
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      channelIn.transferTo(0, channelIn.size(), channelOut);                
 
      channelIn.close();            
      channelOut.close();            
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }    
}