【问题标题】:ZipInputStream doesn't report *actual* (i.e. compressed) bytes readZipInputStream 不报告读取的*实际*(即压缩)字节
【发布时间】:2010-10-24 00:09:57
【问题描述】:

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

我正在读取来自 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.5Mb(取决于文件的压缩,但可以是任何东西!)。我想知道的是,是否有办法找出从原始inputStream 中读取了多少实际字节? ze.getSize()ze.getCompressedSize() 对于每个压缩条目都返回 -1(即它不知道)。我需要此信息作为进度条,以显示已从网络读取传输的 zip 文件的字节数。

建议?我是否应该将 ZipInputStream 子类化并尝试找出它从包装的 InputStream 中读取了多少字节?

提前致谢!

【问题讨论】:

    标签: java inputstream unzip


    【解决方案1】:
    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
    【解决方案2】:

    谢谢你们!我刚刚完全按照克林特的建议完成了!

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

    现在我想知道我应该给谁打个小“复选标记”给...?

    再次感谢!

    【讨论】:

      【解决方案3】:

      当然,这似乎是合理的。

      基本上有两种选择:读取所有字节,将它们存储(在内存或文件中),计算它们,然后解压缩它们;或者在它们进入时对其进行计数。前者似乎效率低下,后者将需要InputStream 的子类,它能够计算它读取的字节数。我想不出标准库中的一个,但那里可能存在实现 - 再说一遍,编写自己的也很容易。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        猜你喜欢
        • 2012-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多