TruePS
TruePS

Reputation: 523

How can we enhance performance using hooking?

the Java Docs says Java Docs

public class BufferedReader extends Reader

Reads text from a character-input stream, buffering characters so as to provide for the >efficient reading of characters, arrays, and lines.

The buffer size may be specified, or the default size may be used. The default is large >enough for most purposes.

In general, each read request made of a Reader causes a corresponding read request to be >made of the underlying character or byte stream. It is therefore advisable to wrap a >BufferedReader around any Reader whose read() operations may be costly, such as >FileReaders and InputStreamReaders. For example,

BufferedReader in = new BufferedReader(new FileReader("foo.in"));

will buffer the input from the specified file. Without buffering, each invocation of >read() or readLine() could cause bytes to be read from the file, converted into >characters, and then returned, which can be very inefficient.

But by hooking Filereader we are using FileReader's read method to read file which reads one character at a time,So if my file contains 2000 characters FileReader firstly will read 2000 characters one at a time and transfer it to buffer and we will read that from buffer using bufferedreader so How it enhances performance.We could do it using FileReader only?

Upvotes: 0

Views: 112

Answers (4)

Danstahr
Danstahr

Reputation: 4319

The BufferedReader is a common example of using a buffer.

Let's decompose the read() method of BufferedReader (J7u51):

ensureOpen();
for (;;) {
    if (nextChar >= nChars) {
        fill();
        if (nextChar >= nChars)
            return -1;
    }

The fill() method (which calls the underlying reader) is invoked if and only if we ask for more characters than we've got from some previous calls.

    if (skipLF) {
        skipLF = false;
        if (cb[nextChar] == '\n') {
            nextChar++;
            continue;
        }
    }
    return cb[nextChar++];
}

Here we just return the appropriate value.

So BufferedReader always "reads more in case you'd like more later" and then, if you really want more, can give you "the more" efficiently.

Take a look at this example :

YourApp                   BufferedReader (bufferSize=10)        FileReader
read(1 character)   ->
                          buffer empty, load 10 characters  ->  disk latency 10 ms
                                                            <-  return 10 characters
                          buffer filled with 10 characters
                    <-    return 1 character, 9 remaining 
                          in buffer
read(1 character)   ->    
                    <-    return 1 character, 8 remaining 
                          in buffer
.
.
.
read(1 character)   ->    
                    <-    return 1 character, 0 remaining 
                          in buffer

The total execution time of the loop is 10 milliseconds + insignificant Java overhead.

Now, compare it with the unbuffered version :

YourApp                   FileReader

read(1 character)   ->
                          disk latency 10 ms
                    <-    return 1 character
read(1 character)   ->    
                          disk latency 10 ms
                    <-    return 1 character
.
.
.
read(1 character)   ->    
                          disk latency 10 ms
                    <-    return 1 character

The overhead caused by the HDD calls is much bigger than in the previous case.

Upvotes: 2

A4L
A4L

Reputation: 17595

You could imagin it like this:

You are in location A and your data is at location B where A and B are 5km away from each other.

By retieving the data one unit at a time you have to make the travel (read request to be made of the underlying character or byte stream) from A to B each time, thus if you have 100 data units you are going to do the travel 100 times, and this is waht costs time.

Wehen Buffering you are like having a truck and when you do a travel you load some amount of data units (the size of the buffer) onto your load floor (the buffer) so that you don't have to make the travel a lot of times and thus be efficient.

Usually where you open a file for reading you want to read more that one charachter, therefore a BufferedRead is to be prefered.

The same applies for writing too.

EDIT

First off, FileReader does not read itself, it's the underlying input stream which does. In this case FileInputStream.

The BufferedReader manages the FileReasder for you, and it uses in its fill() method the method

abstract public int read(char cbuf[], int off, int len) throws IOException;

of your Reader to fill the buffuer. It does not use the method which reads only a single character! In other word, when the fill method has to do the travel, it retrieves a range of charcters from the underlying input stream and keeps it in memory, so that when you need to read, it first looks in the buffer, consumes it and re-fills it if necessary.

You could achieve the same by calling read(char cbuf[], int off, int len) of FileReader yourself, but then all you will have is a range of charcters which having for example the following text

Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.

may for example look like this

"onsetetur sadipscing elitr,\r\nsed diam nonumy eirmod temp"

and you will have to deal with it to find a line of text if you need one.

But you dont have to because BufferedReader takes care of this for you, and this is one of the reasons why you better write

BufferedReader in = new BufferedReader(new FileReader("foo.in"));

Upvotes: 2

Andrei Nicusan
Andrei Nicusan

Reputation: 4623

Who says FileReader instance will be used to read one character at a time?

The best solution for your question is to go directly to the source code of BufferedReader. If you look into this, you will see that, internally, BufferedReader will call the read(char[],int,int) method of the wrapped FileReader (or whatever Reader it wraps).

Here you have the code for the read method of BufferedReader. The actual call to the wrapped Reader is performed in the fill method. I think it's worth checking it a bit.

Upvotes: 1

Robin Krahl
Robin Krahl

Reputation: 5308

Firstly, BufferedReader does not read the wrapped Reader completely at one time. Instead it reads chunks of a specific size (per default 8192 characters) if required.

Secondly, the reason to use a BufferedReader instead of directly using a FileReader is that accessing a file is much more complex than accessing an object in the memory. So if you read a file line by line, you'd access the file system once per line. Using a BufferedReader, you can reduce the count of read operations and thereby improve the performance of your code.

Upvotes: 1

Related Questions