How to properly extend Java FilterOutputStream class?
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 开发者_Python百科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.
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.
- It has its own reference to the wrapped output stream even though
FilterOutputStream
stores that for you in a protected field calledout
. - It writes
len
bytes to the wrapped stream whenwrite(byte[] b, int off, int len)
is called, but only adds 1 to the number of bytes transferred. - It doesn't increment the bytes transferred in
write(byte b)
.
精彩评论