Scabbard Gaming
Scabbard Gaming

Reputation: 51

ZIP4J Unzipping/Extraction with ProgressBar / Progress Monitor

My question is, how do we achieve putting some progress bar or progress monitoring in unzipping zip file using ZIP4j library and the .extractAll method. I've done a research about this but I did not find any solution for this or maybe I didn't meet the right answer on internet, and I'm here now to ask anyone on how to do it. I'm using GUI Swing framework for testing only. I hope someone can lend their hand answering it. Thank you!

Upvotes: 0

Views: 695

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347204

To my surprise, Zip4J actually has a reasonable concept of a "progression"!

There's a number of ways you might make this work with Swing, but probably the easiest is to use a SwingWorker, which also has a concept of "progression"

See...

for more details

Runnable example...

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (ZipException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private JProgressBar progressBar;

        public TestPane() throws ZipException {
            progressBar = new JProgressBar();
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridBagLayout());
            add(progressBar);

            ZipFile zipFile = new ZipFile(new File("Test.zip"));
            ProgressMonitor monitor = zipFile.getProgressMonitor();
            zipFile.setRunInThread(true);
            Zip4JZorker worker = new Zip4JZorker(monitor);
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    String propertyName = evt.getPropertyName();
                    Object newValue = evt.getNewValue();
                    System.out.println(propertyName + "/" + newValue);
                    if ("progress".equals(propertyName) && newValue instanceof Integer) {
                        int progress = (int) newValue;
                        progressBar.setValue(progress);
                    } else if ("state".equals(propertyName) && newValue instanceof SwingWorker.StateValue) {
                        SwingWorker.StateValue state = (SwingWorker.StateValue) newValue;
                        if (state == SwingWorker.StateValue.DONE) {
                            try {
                                ((SwingWorker)evt.getSource()).get();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                                JOptionPane.showMessageDialog(TestPane.this, "Operation failed", "Error", JOptionPane.ERROR_MESSAGE);
                            }
                        }
                    }
                }
            });
            zipFile.addFolder(new File("/some/folder/you/want/zipped"));
            worker.execute();
        }

    }

    public class Zip4JZorker extends SwingWorker<Void, Void> {

        private ProgressMonitor progressMonitor;

        public Zip4JZorker(ProgressMonitor progressMonitor) {
            this.progressMonitor = progressMonitor;
        }

        @Override
        protected Void doInBackground() throws Exception {
            while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
                //System.out.println("Percentage done: " + progressMonitor.getPercentDone());
                //System.out.println("Current file: " + progressMonitor.getFileName());
                //System.out.println("Current task: " + progressMonitor.getCurrentTask());
                // You could pass on some information to the UI via the
                // publish method
                setProgress(progressMonitor.getPercentDone());
                Thread.sleep(100);
            }
            // Again, you could pass on additional information to the
            // UI via the publish method
            if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
                System.out.println("Successfully added folder to zip");
            } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
                throw progressMonitor.getException();
            } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
                System.out.println("Task cancelled");
            }
            return null;
        }

    }
}

Okay, before anyone asks, what's the difference between this an @Abra's answer, the basic answer is, I use setProgress over publish.

publish can then be used to provide additional details, like the current file being processed. This is just a different way to approach the same problem 😉

Upvotes: 1

Abra
Abra

Reputation: 20914

I presume you are referring to this Zip4J.
Here is a demo Swing app that hopefully does what you want.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.progress.ProgressMonitor;

public class Zip4jGui implements Runnable {
    private JFileChooser  fileChooser;
    private JFrame  frame;
    private JProgressBar  progressBar;
    private JTextField  zipFileTextField;

    @Override
    public void run() {
        createAndDisplayGui();
    }

    private void browseFiles(ActionEvent event) {
        if (fileChooser == null) {
            fileChooser = new JFileChooser();
        }
        int choice = fileChooser.showOpenDialog(frame);
        if (choice == JFileChooser.APPROVE_OPTION) {
            File zipFile = fileChooser.getSelectedFile();
            zipFileTextField.setText(zipFile.getAbsolutePath());
        }
    }

    private void createAndDisplayGui() {
        frame = new JFrame("Zip4J");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createProgressPanel(), BorderLayout.PAGE_START);
        frame.add(createFilePanel(), BorderLayout.CENTER);
        frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createButtonsPanel() {
        JPanel buttonsPanel = new JPanel();
        JButton extractButton = new JButton("Extract");
        extractButton.addActionListener(this::extractZip);
        buttonsPanel.add(extractButton);
        return buttonsPanel;
    }

    private JPanel createFilePanel() {
        JPanel filePanel = new JPanel();
        JLabel zipFileLabel = new JLabel("ZIP File");
        filePanel.add(zipFileLabel);
        zipFileTextField = new JTextField(20);
        filePanel.add(zipFileTextField);
        JButton browseButton = new JButton("Browse...");
        browseButton.addActionListener(this::browseFiles);
        filePanel.add(browseButton);
        return filePanel;
    }

    private JPanel createProgressPanel() {
        JPanel progressPanel = new JPanel();
        JLabel progressLabel = new JLabel("Progress");
        progressPanel.add(progressLabel);
        progressBar = new JProgressBar(0, 100);
        progressPanel.add(progressBar);
        return progressPanel;
    }

    private void extractZip(ActionEvent event) {
        XtrctTsk task = new XtrctTsk();
        task.execute();
    }

    private class XtrctTsk extends SwingWorker<Void, Integer> {
        private ProgressMonitor  progressMonitor;

        @Override
        protected Void doInBackground() throws Exception {
            String path = zipFileTextField.getText();
            File f = new File(path);
            try (ZipFile zipFile = new ZipFile(f)) {
                progressMonitor = zipFile.getProgressMonitor();
                zipFile.setRunInThread(true);
                File dir = f.getParentFile();
                zipFile.extractAll(dir.getAbsolutePath());
                while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
                    int done = progressMonitor.getPercentDone();
                    System.out.println("done: " + done);
                    publish(done);
                    try {
                        Thread.sleep(100);
                    }
                    catch (InterruptedException xInterrupted) {
                        // Safe to ignore (I think).
                        // xInterrupted.printStackTrace();
                    }
                }
            }
            return null;
        }

        protected void done() {
            progressBar.setValue(100);
            JOptionPane.showMessageDialog(frame,
                                          "Extraction ended.",
                                          progressMonitor.getResult().toString(),
                                          JOptionPane.INFORMATION_MESSAGE);
        }

        protected void process(List<Integer> percents) {
            System.out.println("percents = " + percents);
            if (percents != null) {
                int size = percents.size();
                System.out.println("size = " + size);
                if (size > 0) {
                    progressBar.setValue(percents.get(size - 1));
                }
            }
        }
    }

    public static void main(String[] args) {
        Zip4jGui instance = new Zip4jGui();
        EventQueue.invokeLater(instance);
    }
}

This is how it looks when I run it.

screen capture

Refer to the following.

Upvotes: 3

Related Questions