Does BufferedReader.ready() method ensure that readLine() method does not return NULL?
Asked Answered
M

4

13

I have such code to read a text file using BufferedReader:

BufferedReader reader=null;
    try {
        reader = new BufferedReader(new FileReader("file1.txt"));

        while (reader.ready()) {
            final String line = reader.readLine();
            System.out.println("<"+line+">");
        } catch (..)
    {
        ...
    }

It works correctly but Findbugs reports a warning:

NP_DEREFERENCE_OF_READLINE_VALUE : The result of invoking readLine() is dereferenced without checking to see if the result is null. If there are no more lines of text to read, readLine() will return null and dereferencing that will generate a null pointer exception.

When I change FileReader to StringReader, i.e.

BufferedReader reader=null;
    try {
        reader = new BufferedReader(new StringReader("ABCD"));

        while (reader.ready()) {
            final String line = reader.readLine();
            System.out.println("<"+line+">");
        } catch (..)
    {
        ...
    }

the readLine method returns null while the ready method always returns true - indeed this is an infinite loop.

This seems that the readLine may return null even if ready returns true. But why does the behavior differ for different Readers?

UPDATE:

I do know the normal way to read a text file (just like Peter and Ali illustrated). but I read that piece of code from my colleague and realized that I don't know the ready method. Then I read the JavaDoc, but don't understand block. Then I did a test and posted this question. So, the better way to put this question might be:

When will the input be blocking? How to use the ready method (or why not to use it)? Why do those 2 Readers (FileReader and StringReader) behave differently with regards to the ready method?

Maurreen answered 9/3, 2011 at 11:4 Comment(0)
K
18

The ready method tells us if the Stream is ready to be read.

Imagine your stream is reading data from a network socket. In this case, the stream may not have ended, because the socket has not been closed, yet it may not be ready for the next chunk of data, because the other end of the socket has not pushed any more data.

In the above scenario, we cannot read any more data until the remote end pushes it, so we have to wait for the data to become available, or for the socket to be closed. The ready() method tells us when the data is available.

Katherinakatherine answered 10/3, 2011 at 5:12 Comment(0)
R
14

The Reader.ready() and InputStream.available() rarely work as you might like, and I don't suggest you use them. To read a file you should use

String line;
while ((line = reader.readLine()) != null)
    System.out.println("<"+line+">");
Regardful answered 9/3, 2011 at 11:11 Comment(4)
code hangs forever on that reader.readline() line. Any suggestions?Gaddis
That means the other end is is not sending a new line (possible any thing else)Regardful
nah, that's not it; I did it in openssl on the command line just fineGaddis
@Gaddis I assume openssl if not send plain text with a newline at the end.Regardful
P
7

Here's what the Javadocs have to say:

Tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.

So a BufferedReader is considered ready simply if the underlying stream is also ready. Since BufferedReader is a wrapper, this underlying stream could be any Reader implementation; hence the semantics of ready() are those declared on the interface:

Returns true if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block.

So you only really get timing guarantees, i.e. that read() will not block. The result of calling ready() tells you absolutely nothing about the content you'll get back from a read() call, and so cannot be used to elide a null check.

Photoactive answered 9/3, 2011 at 11:11 Comment(1)
Unfortunately for readLine(), ready() only guarentees that one character is available i.e. read() will not block. readLine() will block if there is data but not a complete line.Regardful
C
1

Look at the API for ready.

What you're doing is wrong. ready() only tells you if the stream is readable and valid. Read the comment under return on that link as well.

What you want to do is:

String thisLine;

//Loop across the arguments
for (int i=0; i < args.length; i++) {

  //Open the file for reading
  try {
    BufferedReader br = new BufferedReader(new FileReader(args[i]));
    while ((thisLine = br.readLine()) != null) { // while loop begins here
      System.out.println(thisLine);
    } // end while 
  } // end try
  catch (IOException e) {
    System.err.println("Error: " + e);
  }
} // end for
Cavuoto answered 9/3, 2011 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.