9

I am trying to read text from a web document using a BufferedReader over an InputStreamReader on an URL (to the file on some Apache server).

String result = "";
URL url = new URL("http://someserver.domain/somefile");
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(url.openStream(), "iso-8859-1"));

result += in.readLine();

Now this works just fine. But Obviously I'd like the reader not to just read one line, but as many as there are in the file.
Looking at the BufferedReader API the following code should do just that:

while (in.ready()) {
    result += in.readLine();
}

I.e. read all lines while there are more lines, stop when no more lines are there. This code does not work however - the reader just never reports ready() = true!

I can even print the ready() value right before reading a line (which reads the correct string from the file) but the reader will report 'false'.

Am I doing something wrong? Why does the BufferedReader return 'false' on ready when there is actually stuff to read?

fgysin
  • 11,329
  • 13
  • 61
  • 94
  • I dont know if it is of any importance, but the URL actually points to a location using HTTPS. The certificates are however installed correctly on the server and on the machine which runs the above code. Also the readLine() returns the first line without problems. – fgysin Jan 21 '11 at 14:42
  • It will be ready when there is waiting data, however it won't have waiting data until you perform a read/readLine. Even if there is data waiting, it may not be a complete line so readLine() will block anyway. – Peter Lawrey Jan 21 '11 at 14:51
  • Lotta great answers, thx every one. Sadly I can only mark one as accepted answer. :) – fgysin Jan 26 '11 at 13:35

7 Answers7

10

ready() != has more

ready() does not indicate that there is more data to be read. It only shows if a read will could block the thread. It is likely that it will return false before you read all data.

To find out if there is no more data check if readLine() returns null.

String line = in.readLine();
while(line != null){
   ...
   line = in.readLine();
}
josefx
  • 15,506
  • 6
  • 38
  • 63
8

Another way you can do this that bypasses the in.ready() is something like:

while ((nextLine = in.readLine()) != null) {
  result += nextLine;
}

You will just continue reading until you are done. This way you do not need to worry about the problem with in.ready().

  • I think you've undermined your answer by making it sound like a workaround. What you showed is the most common idiom for reading from a BufferedReader, but more importantly, it's correct. Using the `ready()` method like the OP did is **not** correct. – Alan Moore Mar 22 '15 at 07:20
4

I think the standard way to write this is to just attempt to read the line and verify that it returned sometime. Something like this:

while ((String nextLine = in.readLine()) != null) {
    //System.out.println(nextLine);
    result += nextLine;
}

So you just continue to go until you get null returned from the stream. See here for extra information:

http://download.oracle.com/javase/1.5.0/docs/api/java/io/BufferedReader.html#readLine()

jkovacs
  • 3,470
  • 1
  • 23
  • 24
pseudoramble
  • 2,541
  • 22
  • 28
  • Sorry, I shouldn't say "standard" way but rather the way I've seen most often. – pseudoramble Jan 21 '11 at 14:48
  • Also - don't forget to use a StringBuffer when constructing large strings (or, StringBuilder for non-synchronized operations): http://download.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuffer.html – pseudoramble Jan 21 '11 at 14:51
  • 5
    No, that's pretty standard although it's not valid Java (`String` instead of `string` and that declaration needs to be outside of the expression). The idiom I use is `for (String l = null; (l = in.readLine()) != null; ) {` – Mark Peters Jan 21 '11 at 14:51
  • Ah, my mistake. Getting my C# and Java mixed up I guess! Sorry about that @Glenn Nelson. – pseudoramble Jan 21 '11 at 14:56
  • Let's say, it's the most confusing way how to write it. It comes from times the C compilers had hard times to optimize anything at all, so you had to help them using assignments as values and similar funny things. When written correctly, it leads to the String being visible in a too large scope. However -- what has it to do with ready() not working??? – maaartinus Jan 21 '11 at 15:04
  • `for (String nextLine = reader.readLine(); nextLine != null; nextLine = reader.readLine()) {}` – valijon Sep 22 '18 at 07:56
1

The BufferedReader.ready() method is behaving as specified:

The Reader.ready() javadoc says the following:

[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.

Then the BufferedReader.ready() javadoc says the following:

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.

If you put these two together, it is clear that BufferedReader.ready() can return false in situations where are characters available. In short, you shouldn't rely on ready() to test for logical end-of-file or end-of-stream.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

If you want to use in.ready(), the following worked for me well:

    for (int i = 0; i < 10; i++) {
        System.out.println("is InputStreamReader ready: " + in.ready());
        if (!in.ready()) {
            Thread.sleep(1000);
        } else {
            break;
        }
    }
15412s
  • 3,298
  • 5
  • 28
  • 38
0

This is what we have been using consistently for years - not sure if it is the "standard" method. I'd like to hear comments about the pros and cons of using URL.openURLStream() directly, and if that is causing the OP's problems. This code works for both HTTP and HTTPS connections.

 URL  getURL = new URL (servletURL.toString() + identifier+"?"+key+"="+value);      
 URLConnection uConn = getURL.openConnection();

 BufferedReader br = new BufferedReader (new
                            InputStreamReader (uConn.getInputStream()));
 for (String s = br.readLine() ; s != null ; s = br.readLine()) {
      System.out.println ("[ServletOut] " + s);
      // do stuff with s
 }               
 br.close();
Manidip Sengupta
  • 3,573
  • 5
  • 25
  • 27
0

Basically the BufferedReader.ready() method can be used for checking whether the underlying stream is ready for providing data to the method caller.... else we can wait the thread for some time till it becomes ready.

But the real problem is that after we completely read the data stream, it will throw false.. so we didn't know whether the stream is fully read OR underlying stream is busy....

jacobs
  • 1
  • Welcome to StackOverflow. Please be sure to check out how to use [Markdown](http://en.wikipedia.org/wiki/Markdown) formatting. It'll make your answers more usable to others. – marko Nov 16 '12 at 19:06