ZipInputStream没有报告*实际*(即压缩的)字节数读取。

4

我很喜欢这个网站!我的问题如下:

我正在读取一个通过HTTP“PUT”请求从网络传输的zip文件。请求头告诉我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.5Mb(取决于文件的压缩情况,但也可能是其他大小!)。我想知道是否有一种方法可以找出从原始inputStream读取了多少实际字节?每个压缩条目的ze.getSize()ze.getCompressedSize()都返回-1(即它不知道)。我需要此信息以显示进度栏,以显示已从网络中读取了多少传输的zip文件字节。

有什么建议吗?也许我应该子类化ZipInputStream并尝试找出它从其包装的InputStream中读取了多少字节?

谢谢您提前的帮助!

4个回答

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

为什么构造函数是“protected”? - Agung Pratama

2
谢谢你们两个!我刚刚完成了Clint建议的几乎完全一样的东西!
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

好的,那似乎很合理。

基本上有两个选择:读取所有字节,将它们存储(在内存或文件中),计算它们,然后解压缩它们;或者在读取时计算它们。前者似乎效率低下,而后者将需要一个具有计算读取字节数能力的InputStream子类。我想不到标准库中有这样的实现,但可能存在其他实现 - 不过编写自己的实现也相当容易。


-1

这就是我所做的...不需要覆盖任何东西。

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

http://docs.oracle.com/javase/7/docs/api/java/util/zip/ZipInputStream.html#available() 在当前条目数据已到达EOF后返回0,否则始终返回1。 程序不应该依赖此方法返回可以无阻塞读取的实际字节数。 - Frank Xu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接