Reputation: 523
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
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
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
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
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