1

Currently I'm trying to get a progress information during the decompressing process of a zip file.

I'm taking a deeper look into commons-compress which has all needed compress/decompress algos etc. but what I'm missing is a thing to get a progress information somehow...during the unzip process to give a user an information for example on console etc. Am I Missing something ? Maybe I haven't read the docs carefully enough ?

I already taken a look at things by using java.util.Zip but commons compress is a more general library which supports different formats...

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
khmarbaise
  • 92,914
  • 28
  • 189
  • 235
  • I think the real problem is how to know the exact decompressed size. Perhaps you can take it as a percent of the zip size and then you can compute an approximated 'progress' as you read each buffer from the decompressed stream – rafalopez79 Mar 12 '18 at 11:05

1 Answers1

1

Tracking the input read byte count and comparing it with the compressed file size you have a indicator of the decompressing progress.

I´m pasting this class as an approximation to the solution, it wraps a FileInputStream with a wrapper that tracks the read size and invokes a callback to print the progress in the console:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPInputStream;

public final class Gz {

    protected static interface GzProgress {

        public void progress(long read, long max);
    }

    protected static final class GzConsoleProgress implements GzProgress {

        protected final int incr;
        protected int lastPercent;

        protected GzConsoleProgress(int incr) {
            this.incr = incr;
            this.lastPercent = 0;
        }

        @Override
        public void progress(long read, long max) {
            final int percent = (int) (read * 100 / max);
            if (percent >= lastPercent + incr) {
                final int items = (percent - lastPercent) / incr;
                for (int i = 0; i < items; i++) {
                    System.out.print('#');
                }
                lastPercent = percent % incr == 0 ? percent : (percent - percent % incr);
            }
        }
    }

    protected static final class GzProgressInputStream extends BufferedInputStream {

        protected final long max;
        protected long read;
        protected final GzProgress progress;
        protected boolean end;

        protected GzProgressInputStream(InputStream is, long max, GzProgress progress) {
            super(is);
            this.max = max;
            this.read = 0;
            this.progress = progress;
            end = false;
        }

        @Override
        public synchronized int read(byte[] b, int off, int len) throws IOException {
            final int r = super.read(b, off, len);
            if (r > 0) {
                read += r;
                progress.progress(read, max);
                end = read == max;
            }
            return r;
        }

        @Override
        public void close() throws IOException {
            try {
                super.close();
            } finally {
                if (!end) {
                    progress.progress(max, max);
                }
            }
        }
    }

    public static void main(String[] args) {
        if (args == null || args.length == 0) {
            System.out.println("Usage: java " + Gz.class.getName() + " file1.gz file2.gz ...");
        } else {
            final int progressPercent = 10;
            for (final String filename : args) {
                final File file = new File(filename);
                if (file.exists() && filename.toLowerCase().endsWith(".gz")) {
                    final File outFile = new File(filename.replaceAll(".gz$", ""));
                    System.out.println("Extracting " + filename + " ...");
                    final long length = file.length();
                    try (final InputStream is = new GZIPInputStream(new GzProgressInputStream(new FileInputStream(file),
                            length, new GzConsoleProgress(progressPercent)));
                            final OutputStream os = new BufferedOutputStream(new FileOutputStream(outFile))) {
                        final byte[] buff = new byte[512];
                        int r = 0;
                        while ((r = (is.read(buff))) != -1) {
                            os.write(buff, 0, r);
                        }
                    } catch (final IOException e) {
                        System.err.println("Error extracting " + filename + ": " + e.getMessage());
                    }
                    System.out.println();
                }
            }
        }
    }
}

I hope to be helpful.

rafalopez79
  • 2,046
  • 4
  • 27
  • 23