ZipInputStream не сообщает о * фактических * (т.е. сжатых) прочитанных байтах - PullRequest
4 голосов
/ 05 мая 2009

Люблю этот сайт! Моя проблема заключается в следующем:

Я читаю 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 ]

2 голосов
/ 05 мая 2009
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));
2 голосов
/ 05 мая 2009

Спасибо вам обоим! Я только что закончил делать в точности то, что предложил Клинт!

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

Теперь мне интересно, кому я должен поставить маленькую "галочку" ...?

Еще раз спасибо!

1 голос
/ 05 мая 2009

Конечно, это кажется разумным.

Существует два основных варианта: прочитать все байты, сохранить их (в памяти или в файле), сосчитать их, а затем распаковать; или посчитайте их по мере их поступления. Первое кажется неэффективным, а второму потребуется подкласс InputStream, который может считать считанные байты. Я не могу придумать ни одного из них в стандартной библиотеке, но реализации, вероятно, уже существуют - с другой стороны, было бы довольно легко написать свою собственную.

0 голосов
/ 01 марта 2012

Это то, что я делаю ... не нужно ничего переопределять.

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