views:

338

answers:

3

Hi all. Love this website! My issue is as follows:

I'm reading a zip file that's coming over a network from an HTTP "PUT" request. The request header tells me that the Content-Length is (say) 1Mb. The following code creates the ZipInputStream, and saves the zip contents to files in the current directory:

ZipInputStream zis = new ZipInputStream(inputStream);
ZipEntry ze;
long totalBytesRead = 0;
while ((ze = zis.getNextEntry()) != null) {
    BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(ze.getName()));
    byte[] buffer = new byte[4096];
    int i;
    while ((i = zis.read(buffer)) != -1) {
     totalBytesRead+=i;
     outStream.write(buffer,0,i);
    } 
    outStream.close();
}
inputStream.close();

When all is said and done, totalBytesRead is equal to about 1.5Mb (depending on compression of the files, could be anything though!). What I'd like to know is if there is a way to find out how many actual bytes have been read from the original inputStream? Both ze.getSize() and ze.getCompressedSize() return -1 for every zipped entry (i.e. it doesn't know). I need this info for a progress bar to show how many bytes of the transmitted zip file have been read off the network.

Suggestions? Should I perhaps subclass ZipInputStream and try to find out how many bytes it's reading from it's wrapped InputStream?

Thanks in advance!

+1  A: 

Sure, that seems reasonable.

There are basically two options: read all the bytes, store them (in memory or a file), count them, then decompress them; or count them as they come in. The former seems inefficient, and the latter will require a subclass of InputStream which has the ability to count the bytes it reads. I can't think of one in the standard library, but implementations probably exist out there - then again it'd be pretty easy to write your own.

David Zaslavsky
+1  A: 
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 
 */

/**
 * @author clint
 * 
 */
public class ByteCountingInputStream extends FilterInputStream {

  public int totalRead = 0;

  /**
   * @param in
   */
  protected ByteCountingInputStream(InputStream in) {
    super(in);
    // TODO Auto-generated constructor stub
  }

  /* (non-Javadoc)
   * @see java.io.FilterInputStream#read()
   */
  @Override
  public int read() throws IOException {
    int ret = super.read();
    totalRead++;
    return ret;
  }

  /* (non-Javadoc)
   * @see java.io.FilterInputStream#read(byte[], int, int)
   */
  @Override
  public int read(byte[] b, int off, int len) throws IOException {
    int ret = super.read(b, off, len);
    totalRead += ret;
    return ret;
  }

  /* (non-Javadoc)
   * @see java.io.FilterInputStream#read(byte[])
   */
  @Override
  public int read(byte[] b) throws IOException {
    int ret = super.read(b);
    totalRead += ret;
    return ret;
  }

  /* (non-Javadoc)
   * @see java.io.FilterInputStream#skip(long)
   */
  @Override
  public long skip(long n) throws IOException {
    //What to do?
    return super.skip(n);
  }

  /**
   * @return the totalRead
   */
  protected int getTotalRead() {
    return this.totalRead;
  }

}

This goes in between like

ZipInputStream zis = new ZipInputStream(new ByteCountingInputStream(inputStream));
Clint
A: 

Thank you both! I just finished making pretty much exactly what Clint suggested!

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class CountingInputStream extends FilterInputStream {

    private long totalBytes = 0;

    protected CountingInputStream(InputStream in) {
     super(in);
    }

    public int getTotalBytesRead() {
     return totalBytes;
    }

    @Override
    public int read() throws IOException {
     int byteValue = super.read();
     if (byteValue != -1) totalBytes++;
     return byteValue;
    }

    @Override
    public int read(byte[] b) throws IOException {
     int bytesRead = super.read(b);
     if (bytesRead != -1) totalBytes+=bytesRead;
     return bytesRead;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
     int bytesRead = super.read(b,off,len);
     if (bytesRead != -1) totalBytes+=bytesRead;
     return bytesRead;
    }
}

Now I wonder who I should give the little "check-mark" to...?

Thanks again!

Doc Zaius
Yes, the -1 check is a good adaptation.
Clint