Mohammad Karmi
Mohammad Karmi

Reputation: 1455

BufferedReader amount of bytes read

Per my knowledge the buffered reader is way optimized than non buffered as each read will be done from memory , no need for I/O read/write from disk/network each time.

So I was reading the answers here :

Specific difference between bufferedreader and filereader

I got confused by the second answer which seems to have high votes :

When the "read" instruction is given to the BufferedReader object, it uses the FileReader object to read the data from the file. When an instruction is given, the FileReader object reads 2 (or 4) bytes at a time and returns the data to the BufferedReader and the reader keeps doing that until it hits '\n' or '\r\n' (The end of the line symbol). Once a line is buffered, the reader waits patiently, until the instruction to buffer the next line is given.

is that correct ? I would think we lost the whole idea about buffer reader, if the buffer need to do multiple 2 bytes read then I can just use the file reader and can use that too. The idea in buffered reader it should read large block at a time so the number of I/O access will be much less than file reader.

can anyone correct me if I'm wrong ?

Upvotes: 1

Views: 1928

Answers (3)

Hank Lenzi
Hank Lenzi

Reputation: 91

Let's do an experiment with a tiny UTF-8 encoded file in Linux, and then create its hexdump, and try to understand what goes on:

$ echo "Try my delicious pork-chop ribs!" > ribs.txt
$ cat ribs.txt | xxd -g 1 > ribs.hexdump`
$ cat ribs.hexdump 
00000000: 54 72 79 20 6d 79 20 64 65 6c 69 63 69 6f 75 73  Try my delicious
00000010: 20 70 6f 72 6b 2d 63 68 6f 70 20 72 69 62 73 21   pork-chop ribs!
00000020: 0a    
                                       .

Now, use jshell, and create instances for FileReader, BufferedReader and StringBuilder objects:

    jshell> FileReader afr = new FileReader("/path/to/file/ribs.txt/")
    afr ==> java.io.FileReader@3d012ddd
'    
    jshell> BufferedReader bfr = new BufferedReader(afr)
    bfr ==> java.io.BufferedReader@6504e3b2
    
    jshell> StringBuilder ct = new StringBuilder()
    ct ==> 

` 'ct' is the content of the StringBuilder object. It's empty right now. So, let's construct a for loop that iterates by 8 at a time, as see what it does:

for (int i=0; i < 7; i++) {
if ((value = bfr.read()) != -1) { ct.append((char) value); }
i++;
}

Which in the jshell we do: `

    jshell> int value;
    value ==> 0
    
    jshell> for (int i=0; i < 7; i++) {
       ...> if ((value = bfr.read()) != -1) { ct.append((char) value); }
       ...> i++;
       ...> }
`

Let's look at the content: `

jshell> ct
ct ==> Try 

` We can look at our hexdump file we previously prepared to try to understand where we're at:

`
    00000000: 54 72 79 20 6d 79 20 64 65 6c 69 63 69 6f 75 73  Try my delicious
              T  r  y  SP (<---- YOU ARE HERE)
`

Let's confirm this with another iteration cycle:

`     
    jshell> for (int i=0; i < 7; i++) {
       ...> if ((value = bfr.read()) != -1) { ct.append((char) value); }
       ...> i++;
       ...> }
    
    jshell> ct
    ct ==> Try my d
    
    00000000: 54 72 79 20 6d 79 20 64 65 6c 69 63 69 6f 75 73  Try my delicious
              T  r  y  SP m  y  SP d (<---- YOU ARE HERE)
`

See: you asked for 8 characters, but it gave you 4 characters (2 bytes each)! FileReader does, indeed, read 2 bytes at a time! -- Hank

Upvotes: 0

Caius Jard
Caius Jard

Reputation: 74605

The point he's making is that FileInputStream reads N bytes at a time and takes no interest in the data it reads. BufferedReader eventually uses FileInputStream (when reading a file) and does the repetitive read part but it does take an interest in the bytes it reads, treating them as character data (encoding considerations etc) chopping them up into lines

Sure, you can write your own, and not use BufferedReader, but you can say the same about anything in computing: "I didn't like NVidia's display driver, so I sat down and spent 3 years writing my own. Now I'm starting a new operating system. Be done for when quantum computers are mainstream" - nearly no-one does this; it's called reinventing the wheel and there's a reason why we don't do it: for the most part, the wheels other people invented are already fine for our purposes/better than we have time to do ourselves

Note; you seem to be taking issue with the assertion that BufferedReader ultimately reads from the data source a byte or two at a time. It probably doesn't, but I don't think that's the point the guy is making (the language used in the post is rather vague). Regardless of how it reads bytes from an InputStream/Reader, a BufferedReader will certainly inspect the data that it reads on a character-by-character basis as it looks for newlines, so it can make ReadLine() work. It will do this independently of the strategy that it uses to read the file (maybe it repeatedly reads in 4096 byte chunks, but it will certainly have to process the data byte by byte as it interprets it)

Ultimately consider that file access is cached and coalescing of reads may occur at many levels: calling ReaderX.Read() will almost certainly not cause a hard disk to stop everything it's doing, go to a certain sector, read a single byte, and go back to what it was doing before. You might thus issue a million calls to Read() one char that cause no more hard disk thrashing than a single call to Read() into a megabyte buffer

Upvotes: 0

Masked Man
Masked Man

Reputation: 2538

Take a look at BufferedReader javadoc:

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. Programs that use DataInputStreams for textual input can be localized by replacing each DataInputStream with an appropriate BufferedReader.

So it buffers the data beforehand from the underlying resource and consequent read instructions use the buffer for efficiency.

Upvotes: 1

Related Questions