-2

im trying to read from a file using FileReader but the program goes in an infinite loop : here is my code:

import java.io.FileReader;

public class Test {
    public static void main(String[] args)  {
        try(FileReader f = new FileReader("sales.dat");){
            char ch = (char)f.read();
            while(ch != -1){
                ch = (char)f.read();
                System.out.print(ch);
            }
        }catch (Exception e){
        }
    }
}

and why is it not efficient to read files using just FileReader and it's better to use a BufferedReader object

Danielson
  • 2,605
  • 2
  • 28
  • 51

3 Answers3

3

The range for char is between 0 and 65535 so it cannot be -1 so char != -1 is always true.

while(int ch; (ch = f.read()) >= 0;)
   System.out.print((char) ch);

This will check the value is non-negative before converting to a char

why is it not efficient to read files using just FileReader and it's better to use a BufferedReader object

BufferedReader uses FileReader so perhaps the question should be; why not use FileReader alone?

The answers is; calling the operating system is expensive. Each call can be several micro-seconds whereas an process memory access can be nano-seconds.

By using a buffer e.g. with BufferedReader, you call the OS far less (up to 1/8192 the amount by default) and this improves the efficiency of getting each byte of data.

In the example above, it hardly matters. While calling FileReader is expensive, it is cheap by comparison to writing to the console. Writing to the console is the only thing which matters in terms of performance here.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

You could, instead, read per line, like this

final File file = new File("your_file");
try (final InputStream fileStream = new FileInputStream(file.getAbsolutePath()); final Reader decoder = new InputStreamReader(fileStream);
        final BufferedReader buffered = new BufferedReader(decoder)) {
    String line;
    while ((line = buffered.readLine()) != null) {
        // do stuff
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

ps. don't know about your sub-question

Danielson
  • 2,605
  • 2
  • 28
  • 51
  • You need to start somewhere, and I use this code for all reading... Upside of BufferedReader (and stuff) is that you can give it a zipStream, or whatever stream for that matter... – Danielson Jun 26 '15 at 15:00
0

You can't get a negative char value, so the check for less than -1 will always be false.

When using a subclass InputStreamReader, you should rely on ready() to check if you have reached the end of the stream.

while(reader.ready()){
    // do stuff
}

Using buffered streams is faster because it reduces the number of OS IO calls. If you have a file with 1 million bytes and read it one byte at a time, for each non-buffered call the JVM needs to request a read from the OS. That's 1 million times the Java process requests reads from the operating system. With a buffered stream, it attempts to fill its buffer in a single read. So even if you request 1 byte, the underlying stream will have N number of bytes in memory, reducing the number of calls to the underlying OS by roughly FILE_SIZE/BUFFER_SIZE. For the 1 MB file, if the buffer size is 1024, and it is able to fill each time, the number of OS calls will be 1M/1K, or 1000 reads vs 1 million.

MadConan
  • 3,749
  • 1
  • 16
  • 27