Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is using BufferedInputStream to read a file byte by byte faster than using FileInputStream?

I was trying to read a file into an array by using FileInputStream, and an ~800KB file took about 3 seconds to read into memory. I then tried the same code except with the FileInputStream wrapped into a BufferedInputStream and it took about 76 milliseconds. Why is reading a file byte by byte done so much faster with a BufferedInputStream even though I'm still reading it byte by byte? Here's the code (the rest of the code is entirely irrelevant). Note that this is the "fast" code. You can just remove the BufferedInputStream if you want the "slow" code:

InputStream is = null;      try {         is = new BufferedInputStream(new FileInputStream(file));          int[] fileArr = new int[(int) file.length()];          for (int i = 0, temp = 0; (temp = is.read()) != -1; i++) {             fileArr[i] = temp;         } 

BufferedInputStream is over 30 times faster. Far more than that. So, why is this, and is it possible to make this code more efficient (without using any external libraries)?

like image 613
ZimZim Avatar asked Sep 03 '13 19:09

ZimZim


People also ask

Why is BufferedInputStream faster?

With a BufferedInputStream , the method delegates to an overloaded read() method that reads 8192 amount of bytes and buffers them until they are needed. It still returns only the single byte (but keeps the others in reserve). This way the BufferedInputStream makes less native calls to the OS to read from the file.

What is the difference between BufferedInputStream and FileInputStream?

Key differences: BufferedInputStream is buffered, but FileInputStream is not. A BufferedInputStream reads from another InputStream , but a FileInputStream reads from a file1.

What is the purpose of BufferedInputStream?

A BufferedInputStream adds functionality to another input stream-namely, the ability to buffer the input and to support the mark and reset methods. When the BufferedInputStream is created, an internal buffer array is created.

What is the difference between BufferedReader and BufferedInputStream?

The main difference between BufferedReader and BufferedInputStream is that BufferedReader reads characters (text), whereas the BufferedInputStream reads raw bytes. The Java BufferedReader class is a subclass of the Java Reader class, so you can use a BufferedReader anywhere a Reader is required.


2 Answers

In FileInputStream, the method read() reads a single byte. From the source code:

/**  * Reads a byte of data from this input stream. This method blocks  * if no input is yet available.  *  * @return     the next byte of data, or <code>-1</code> if the end of the  *             file is reached.  * @exception  IOException  if an I/O error occurs.  */ public native int read() throws IOException; 

This is a native call to the OS which uses the disk to read the single byte. This is a heavy operation.

With a BufferedInputStream, the method delegates to an overloaded read() method that reads 8192 amount of bytes and buffers them until they are needed. It still returns only the single byte (but keeps the others in reserve). This way the BufferedInputStream makes less native calls to the OS to read from the file.

For example, your file is 32768 bytes long. To get all the bytes in memory with a FileInputStream, you will require 32768 native calls to the OS. With a BufferedInputStream, you will only require 4, regardless of the number of read() calls you will do (still 32768).

As to how to make it faster, you might want to consider Java 7's NIO FileChannel class, but I have no evidence to support this.


Note: if you used FileInputStream's read(byte[], int, int) method directly instead, with a byte[>8192] you wouldn't need a BufferedInputStream wrapping it.

like image 86
Sotirios Delimanolis Avatar answered Sep 28 '22 06:09

Sotirios Delimanolis


A BufferedInputStream wrapped around a FileInputStream, will request data from the FileInputStream in big chunks (512 bytes or so by default, I think.) Thus if you read 1000 characters one at a time, the FileInputStream will only have to go to the disk twice. This will be much faster!

like image 23
usha Avatar answered Sep 28 '22 06:09

usha