views:

128

answers:

1

I would like to roughly monitor the progress of a file upload. I know that I can override the MultipartEntity and make the writeTo(OutputStream out) method write to a FilterOutputStream class that I created to wrap the default InputStream. For full details on how I did that, see my answer here.

However, upon closer inspection this counts every byte sent twice! I went to the documentation to see what was up. Looks like FilterOutputStream's write(byte[], int, int) method simply calls the FilterOutputStream's write(byte) method in a loop. It recommends subclasses to provide a more efficient method. I would assume this to involve calling the underlying OutputStream's write(byte[], int, int) and hoping that the underlying OutputStream has a better method of pushing bytes onto the stream (doc's recommend subclasses of OutputStream override this method and do a better job than simply looping over the OutputStream#write(byte) method).

This is where I find myself in a predicament. I can't guarantee that the MultipartEntity#writeTo(OutputStream) will always result in a call to OutputStream.write(byte[],int,int), so if I count the bytes sent there then I might miss some that are sent using the write(byte) method. However, I can't count in the write(byte) method, because the OutputStream.write(byte[],int,int) method may never call the write(byte) method.

One answer is to call super.write(byte[],int,int) inside of my subclass's write(byte[],int,int) method. Then, I know that this will simply loop over the write(byte) method, writing one byte at a time. I can then count all bytes written inside of the write(byte) method. However, this is inefficient, and the docs directly recommend against it. I am sure that some of the subclasses of OutputStream manage to write multiple bytes to the stream at once, so it's silly not to use that advantage.

So, how do I properly override FilterOutputStream to be both efficient and count all bytes sent?

Sorry if this is long, I have made it a wiki in case anyone can describe the issue better than I.

+1  A: 

Just call write(byte[] b, int off, int len) on the underlying stream when the same method is called on your counting stream. That will never cause the write(byte b) method on the counting stream to be called.

Also, your CountingOutputStream in the linked answer has a number of other issues.

  1. It has its own reference to the wrapped output stream even though FilterOutputStream stores that for you in a protected field called out.
  2. It writes len bytes to the wrapped stream when write(byte[] b, int off, int len) is called, but only adds 1 to the number of bytes transferred.
  3. It doesn't increment the bytes transferred in write(byte b).
ColinD
Colin, thanks a lot! This makes it a lot more clear :)
Hamy