ZipInputStream no reporta * reales * (es decir, comprimidos) bytes leídos

Me encanta este sitio web! Mi problema es el siguiente:

Estoy leyendo un archivo zip que viene a través de una red desde una solicitud HTTP “PUT”. El encabezado de la solicitud me dice que la longitud del contenido es (digamos) 1Mb. El siguiente código crea el ZipInputStream y guarda el contenido del archivo zip en los archivos en el directorio actual:

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(); 

Cuando todo está dicho y hecho, totalBytesRead es igual a aproximadamente 1.5Mb (dependiendo de la compresión de los archivos, ¡podría ser cualquier cosa!). Lo que me gustaría saber es si hay una manera de averiguar cuántos bytes reales se han leído desde inputStream original. Tanto ze.getSize() como ze.getCompressedSize() devuelven -1 para cada entrada comprimida (es decir, no se sabe). Necesito esta información para que una barra de progreso muestre cuántos bytes del archivo zip transmitido se han leído fuera de la red.

Sugerencias? ¿Debería tal vez hacer una subclase de ZipInputStream e intentar averiguar cuántos bytes está leyendo de su InputStream envuelto?

¡Gracias por adelantado!

Claro, eso parece razonable.

Existen básicamente dos opciones: leer todos los bytes, almacenarlos (en la memoria o en un archivo), contarlos y luego descomprimirlos; o cuéntelos a medida que ingresan. El primero parece ineficiente, y el último requerirá una subclase de InputStream que tiene la capacidad de contar los bytes que lee. No puedo pensar en uno en la biblioteca estándar, pero es probable que existan implementaciones por ahí, pero de nuevo sería bastante fácil escribir el tuyo.

 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; } } 

Esto va en medio como

 ZipInputStream zis = new ZipInputStream(new ByteCountingInputStream(inputStream)); 

¡Gracias a los dos! ¡Acabo de terminar de hacer casi exactamente lo que Clint sugirió!

 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; } } 

¿Ahora me pregunto a quién debo darle la pequeña “marca de verificación” para …?

¡Gracias de nuevo!

Esto es lo que hago … no hay necesidad de anular nada.

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