ZipInputStream не сообщает о * фактическом * (т.е. сжатом) прочитанном байте
Люблю этот сайт! Моя проблема заключается в следующем:
Я читаю zip-файл, поступающий по сети из HTTP-запроса "PUT". Заголовок запроса говорит мне, что Content-Length (скажем) 1Mb. Следующий код создает ZipInputStream и сохраняет содержимое zip в файлы в текущем каталоге:
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();
Когда все сказано и сделано, totalBytesRead
равен примерно 1,5 МБ (в зависимости от сжатия файлов может быть что угодно!). То, что я хотел бы знать, есть ли способ узнать, сколько фактических байтов было прочитано из оригинала inputStream
? И то и другое ze.getSize()
а также ze.getCompressedSize()
вернуть -1 для каждой заархивированной записи (то есть она не знает). Мне нужна эта информация для индикатора выполнения, чтобы показать, сколько байтов переданного zip-файла было считано из сети.
Предложения? Должен ли я, возможно, создать подкласс ZipInputStream и попытаться выяснить, сколько байтов он читает из упакованного InputStream?
Заранее спасибо!
4 ответа
Конечно, это кажется разумным.
Есть два основных варианта: прочитать все байты, сохранить их (в памяти или в файле), сосчитать их, затем распаковать; или считать их по мере их поступления. Первое кажется неэффективным, а второму потребуется подкласс InputStream
который имеет возможность считать байты, которые он читает. Я не могу придумать ни одного из них в стандартной библиотеке, но реализации, вероятно, уже существуют - опять же, было бы довольно легко написать свою собственную.
Спасибо вам обоим! Я только что закончил делать в точности то, что предложил Клинт!
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;
}
}
Теперь мне интересно, кому я должен поставить маленькую "галочку"...?
Еще раз спасибо!
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;
}
}
Это идет между как
ZipInputStream zis = new ZipInputStream(new ByteCountingInputStream(inputStream));
Это то, что я делаю... не нужно ничего переопределять.
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();