views:

327

answers:

3

Hello,

I have this piece of code which I'm hoping will be able to tell me how much data I have downloaded (and soon put it in a progress bar), and then parse the results through my Sax Parser. If I comment out basically everything above the //xr.parse(new InputSource(request.getInputStream())); line and swap the xr.parse's over, it works fine. But at the moment, my Sax parser tells me I have nothing. Is it something to do with is.read (buffer) section?

Also, just as a note, request is a HttpURLConnection with various signatures.

                 /*Input stream to read from our connection*/ 
                 InputStream is = request.getInputStream();
                 /*we make a 2 Kb buffer to accelerate the download, instead of reading the file a byte at once*/ 
                 byte [  ]  buffer = new byte [ 2048 ] ;

                 /*How many bytes do we have already downloaded*/ 
                 int totBytes,bytes,sumBytes = 0; 
                 totBytes = request.getContentLength () ; 

                 while  ( true )  {  

                     /*How many bytes we got*/ 
                         bytes = is.read (buffer);

                         /*If no more byte, we're done with the download*/ 
                         if  ( bytes  <= 0 )  break;       

                         sumBytes+= bytes;

                         Log.v("XML", sumBytes + " of " + totBytes + " " + (  ( float ) sumBytes/ ( float ) totBytes ) *100 + "% done" ); 


                 }
                 /* Parse the xml-data from our URL. */
                 // OLD, and works if comment all the above 
                 //xr.parse(new InputSource(request.getInputStream()));
                 xr.parse(new InputSource(is))
                 /* Parsing has finished. */;

Can anyone help me at all??

Kind regards,

Andy

A: 

Your while loop is consuming the input stream and leaving nothing for the parser to read.

For what you're trying to do, you might want to look into implementing a FilterInputStream subclass wrapping the input stream.

Don Roby
That sounds very complicated! Any where I may be able to find examples?
Andy Barlow
Actually, it's not all that complicated. There's a stackoverflow question about examples - see http://stackoverflow.com/questions/765473/examples-of-java-i-o-stream-filters
Don Roby
The short answer on how to find examples is to find src.jar in your Java SDK install. As noted in another answer, javax.swing.ProgressMonitorInputStream is a good example to look at, doing exactly what you want to do, but in a Swing context.
Don Roby
A: 

You are building an InputStream over another InputStream that consumes its data before.

If you want to avoid reading just single bytes you could use a BufferedInputStream or different things like a BufferedReader.

In any case it's better to obtain the whole content before parsing it! Unless you need to dynamically parse it.

If you really want to keep it on like you are doing you should create two piped streams:

PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream();

pipeIn.connect(pipeOut);

pipeOut.write(yourBytes);

xr.parse(pipeIn);

Streams in Java, like their name suggest you, doesn't have a precise dimension neither you know when they'll finish so whenever you create an InputStream, if you read from them you cannot then pass the same InputStream to another object because data is already being consumed from the former one.

If you want to do both things (downloading and parsing) together you have to hook between the data received from the HTTPUrlConncection you should:

  • first know the length of the data being downloaded, this can be obtained from HttpUrlConnection header
  • using a custom InputStream that decorates (this is how streams work in Java, see here) updading the progressbar..

Something like:

class MyInputStream extends InputStream
{
  MyInputStream(InputStream is, int total)
  {
    this.total = total;
  }

  public int read()
  {
    stepProgress(1);
    return super.read();
  }

  public int read(byte[] b)
  {
    int l = super.read(b);
    stepProgress(l);
    return l;
  }

  public int read(byte[] b, int off, int len)
  {
    int l = super.read(b, off, len);
    stepProgress(l);
    return l
  }
}



InputStream mis= new MyInputStream(request.getInputStream(), length);
..
xr.parse(mis);
Jack
Well, I know all the data coming back is going to be XML if thats of any help. It would be nice to be able to see a progress of it downloading and I could only find a way to do that with bytes, unless you know another method?
Andy Barlow
How can I save the first run where it gets how much its read, save that to a string... as im sure InputSource accepts strings!
Andy Barlow
+1  A: 

'I could only find a way to do that with bytes, unless you know another method?'.

But you haven't found a method. You've just written code that doesn't work. And you don't want to save the input to a String either. You want to count the bytes while you're parsing them. Otherwise you're just adding latency, i.e. wasting time and slowing everything down. For an example of how to do it right, see javax.swing.ProgressMonitorInputStream. You don't have to use that but you certainly do have to use a FilterInputStream of some sort, probaby one you write yourself, that is wrapped around the request input stream and passed to the parser.

EJP
+1 for pointing at source that actually does the progress monitoring, though he'll need to write a non-swing version.
Don Roby