wood burning stoves 2.0*
The moose likes Java in General and the fly likes Fastest way to read inputstream and recreate it? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of The Java EE 7 Tutorial Volume 1 or Volume 2 this week in the Java EE forum
or jQuery UI in Action in the JavaScript forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Fastest way to read inputstream and recreate it?" Watch "Fastest way to read inputstream and recreate it?" New topic
Author

Fastest way to read inputstream and recreate it?

Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
I've got a class that gets passed an InputStream which it needs to read from and then pass on to another class. The problem: once that stream's been read, the data's no longer in it (it's not a pushback or buffered).

What's the best way "recreate it" and pass it down the line?

My idea was to copy the data into a ByteArrayOutputStream at the same time that I'm reading the data, and then take that output and put it into a ByteArrayInputStream and pass that on. Is this the fastest, most efficient way to do this? Is there a better way? I'm looking for a solution that hopefully is:

1. Efficient, i.e. quick processing speed
2. Takes as little extra memory as possible (since I believe there's no way not to take approx. double the amount of memory, right? - i.e. there's no way to "leave" the data in the same memory space by reading it and "putting it back"?)
3. Looks the same to other classes reading the stream
Deepak Bala
Bartender

Joined: Feb 24, 2006
Posts: 6661
    
    5

Since every class needs to read the same data using this input stream wouldnt it be better if you made a static reference to the byte [] data so that all classes can use it once it is read ?


SCJP 6 articles - SCJP 5/6 mock exams - More SCJP Mocks
Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
Originally posted by John Meyers:
Since every class needs to read the same data using this input stream wouldnt it be better if you made a static reference to the byte [] data so that all classes can use it once it is read ?


I can't do that. My class is a Servlet Filter and the other classes are simply the filters (and servlets and JSPs) called by doFilter(..). So they expect an HttpServletRequest and that it have a ServletInputStream for POSTed data. So I HAVE to pass that (i.e. an InputStream) on down the line.
Edwin Dalorzo
Ranch Hand

Joined: Dec 31, 2004
Posts: 961
If the implementation of InputStream that you are using supports mark and reset you could use those methods to relocate the pointer at the begining of the stream after you have read it.

Simply invoke mark() at the begining of the read method and reset at the end of the reading process and then pass the stream as parameter.

I have not tested this, but it should work.

Does this help?
Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
Originally posted by Edwin Dalorzo:
If the implementation of InputStream that you are using supports mark and reset you could use those methods to relocate the pointer at the begining of the stream after you have read it.

Simply invoke mark() at the begining of the read method and reset at the end of the reading process and then pass the stream as parameter.

I have not tested this, but it should work.

Does this help?


Hmmm, maybe. It would depend on if the implementation of ServletinputStream (for that particular java web server) supports mark. If it doesn't then I'm back to the original problem. So I'll check if it supports mark and if it does than I'll use that, otherwise use the ByteArrayIn/Out streams to copy it?
Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
Yikes. I've looked online and asked here (and a few other boards) and there don't seem to be any good answers out there. I'm sure tons of people must have come across this issue, but there's almost no discussion about it online. Weird.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
In the context of a Filter, it seems that you should be able to create your own ServletInputStream implementation that simply wraps the original ServletInputStream in a BufferedInputStream, and reads from that BIS as necessary. That allows you to also use the mark() and reset() methods as suggested above, which will work for a BIS. To pass this new ServletInputStream on to the FilterChain you'll need to create a HttpRequestWrapper implementation which returns an instance of the ServletInputStream, and pass this HttpRequestWrapper to the FilterChain with doFilter(). Does that help?


"I'm not back." - Bill Harding, Twister
Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
Originally posted by Jim Yingst:
In the context of a Filter, it seems that you should be able to create your own ServletInputStream implementation that simply wraps the original ServletInputStream in a BufferedInputStream, and reads from that BIS as necessary. That allows you to also use the mark() and reset() methods as suggested above, which will work for a BIS. To pass this new ServletInputStream on to the FilterChain you'll need to create a HttpRequestWrapper implementation which returns an instance of the ServletInputStream, and pass this HttpRequestWrapper to the FilterChain with doFilter(). Does that help?


Yes, that definitely helps! That does seem to be a cleaner, more efficient solution than the one I was going to do (and the only one I've found online): use BAOS/BAIS.

Thanks!
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
Would FilterInputStream do the job for you? I only used it once to make an input stream that wrote everything to the log as it read. It has a few overloaded read() methods like:


A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Dan Bizman
Ranch Hand

Joined: Feb 25, 2003
Posts: 387
Originally posted by Stan James:
Would FilterInputStream do the job for you


My main concern is not transforming the data but simply of allowing multiple reads of the stream (which is not allowed normally). So from that standpoint I think a BufferedInputStream wrapping it or a BAOS-BAOIS option might work better. Using FilterInputStream I'd just have to implement what BufferedInputStream would be doing for me anyways (right? or am i missing something?).
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
It really depends what sort of processing you need to do on the stream. For many applications, the FilterInputStream could well be faster, and require less memory. BAIS/BAOS and BufferedInputStream are both storing the data in byte array somewhere so it can be replayed. With FilteredInputStream you don't need to save the data However you're more limited on what you can do, and when you can do it.

For example, let's say you want to use a FilteredInputStream to count the number of bytes that pass through the filter. That's easy to do. However, let's say that the reason you want that info is that you want to insert it into the request header, for any request that does not supply the content length. That's more of a problem, because the FilteredInputStream is not going to know the length of the content until after all the content has been read, either by another filter or by a servlet at the end of the filter chain. At that point, it may well be too late to populate the content length header, since subsequent filters or the servlet may have already tried to read that before reading the content. So in this case, you'd probably need your filter to read the entire content, and set up the new ServletInputStream with BAIS or BufferednputStream before calling doFilter(). FilterInputStream won't help here.

In general I would suggest that if the processing you require can be done with a FilterInputStream, and you're OK that it won't be completed until the other filters or servlet have started reading the content - then use FilteredInputStream, because it's probably faster and uses less memory. But if you can't, then use BufferedInputStream. Or BAOS/BAIS, but I think that may be a little slower as there's more need for recopying of data from one array to another.
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Fastest way to read inputstream and recreate it?