0

I wanted to write a GUI zip/unzip program with Java. The program will be able to compress any combination of file(s) and directory/ies and decompress one or more compressed files.

Now I've just finished the GUI and zip funtion. But the zip funtion seems not to work properly, producing zip files that are corrupted somehow. I couldn't find where exactly the problem is. It seems to be with the compress function or the zipFile function.

when I tested the program, the output is the following:

192-168-1-101:tools user0$ unzip test1.zip

Archive: test1.zip End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive. In the latter case the central directory and zipfile comment will be found on the last disk(s) of this archive.

unzip: cannot find zipfile directory in one of test1.zip or test1.zip.zip, and cannot find test1.zip.ZIP, period.

Thank you very much for your help.

The code is as follows:

package javazip;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.zip.*;

public class JZip {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable () {
            public void run () {
                new JZipFrame();
            }
        });
    }
}

class JZipFrame extends JFrame {
    private JTextArea displayArea;

    public JZipFrame () {
        setTitle("JZip");
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension screenSize = tk.getScreenSize();
        int screenHeight = screenSize.height;
        int screenWidth = screenSize.width;
        setSize(screenWidth / 4, screenHeight / 4);
        setLocation(screenWidth / 4, screenHeight / 4);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JMenuBar menuBar = createMenuBar();
        JScrollPane displayPanel = createDisplayPanel();

        add(displayPanel);
        setJMenuBar(menuBar);

        setVisible(true);
    } 

    private JMenuBar createMenuBar () {
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Operations");
        JMenuItem compressItem = createCompressItem();
        JMenuItem decompressItem = createDecompressItem();
        JMenuItem quitItem = createQuitItem();

        menu.add(compressItem);
        menu.add(decompressItem);
        menu.add(quitItem);
        menuBar.add(menu);

        return menuBar;
    }

    private JScrollPane createDisplayPanel () {
        displayArea = new JTextArea(20, 40);
        displayArea.setMargin(new Insets(5, 5, 5, 5));
        displayArea.setEditable(false);
        JScrollPane scrlPanel = new JScrollPane(displayArea);

        return scrlPanel;
    }

    private JMenuItem createCompressItem () {
        JMenuItem cItem = new JMenuItem("Compression");
        cItem.addActionListener(new ActionListener () {
            public void actionPerformed (ActionEvent event) {
                File[] cChosenItems = selectFilesForCompression();
                compress(cChosenItems);
            }
        });

        return cItem;
    }

    private JMenuItem createDecompressItem () {
        JMenuItem dItem = new JMenuItem("Decompression");
        dItem.addActionListener(new ActionListener () {
            public void actionPerformed (ActionEvent event) {
                File[] dChosenItems = selectFilesForDecompression();
                decompress(dChosenItems);
            }
        });

        return dItem;
    }

    private final File[] selectFilesForCompression () {
        final JFileChooser cChooser = new JFileChooser();
        File[] selectedItems = null;

        cChooser.setMultiSelectionEnabled(true);
        cChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        int cRetVal = cChooser.showOpenDialog(JZipFrame.this);
        if (cRetVal == JFileChooser.APPROVE_OPTION) {
            selectedItems = cChooser.getSelectedFiles();
            for (File item : selectedItems)
                displayArea.append(item.getParent() + System.getProperty("file.separator") 
                                        + item.getName() + "\n");
        }
        return selectedItems;
    }

    private final File[] selectFilesForDecompression () {
        final JFileChooser dChooser = new JFileChooser();
        dChooser.setMultiSelectionEnabled(true);
        dChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        dChooser.addChoosableFileFilter(new FileFilter() {
            public String getDescription () {
                return "ZIP Files (*.zip)";
            }
            public boolean accept (File f) {
                if (f.isDirectory())
                    return true;
                else 
                    return f.getName().toLowerCase().endsWith(".zip");
            }
        });
        int dRetVal = dChooser.showOpenDialog(JZipFrame.this);
        File[] selectedItems = null;

        if (dRetVal == JFileChooser.APPROVE_OPTION) {
            selectedItems = dChooser.getSelectedFiles();
            for (File item : selectedItems)
                displayArea.append(item.getParent() + System.getProperty("file.separator") 
                                        + item.getName() + "\n");
        }
        return selectedItems;
    }

    private JMenuItem createQuitItem () {
        JMenuItem qItem = new JMenuItem("Quit");
        qItem.addActionListener(new ActionListener () {
            @Override
            public void actionPerformed (ActionEvent event) {
                System.exit(0);
            }
        });
        return qItem;
    }

    private final void compress (File[] files) {
        FileOutputStream out = null;
        String zipName = null;

        if (files.length == 1) {
            zipName = files[0].getName();
            if (files[0].isDirectory()) {
                if (zipName.endsWith("/") || zipName.endsWith("\\"))
                    zipName = zipName.substring(0, zipName.length() - 1);
            }
            try {
                String name = zipName.substring(0, zipName.lastIndexOf("."));
                out = new FileOutputStream(name + ".zip");
            }
            catch (FileNotFoundException e) {
                JOptionPane.showMessageDialog(this, e.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
        else {
            try {
                out = new FileOutputStream(files[0].getParent() + "/compressed.zip");
            }
            catch (FileNotFoundException e) {
                JOptionPane.showMessageDialog(this, e.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
        ZipOutputStream zipOut = new ZipOutputStream(out);
        zipOut.setMethod(ZipOutputStream.DEFLATED);
        for (File f : files) {
            try {
                zipFile(f, f.getName(), zipOut);    
            }
            catch (IOException e) {
                JOptionPane.showMessageDialog(this, e.toString(), "Error", JOptionPane.ERROR_MESSAGE);
            }
            displayArea.append("Now processing: " + f.getName() + "\n");
        }
        JOptionPane.showMessageDialog(this, "Compression was successful!", "Message", JOptionPane.INFORMATION_MESSAGE);
    }
    // The problem may be with this function or the one above
    private void zipFile (File file, String fileName, ZipOutputStream zipOut) throws IOException {

        if (file.isHidden()) {
            return;
        }
        if (file.isDirectory()) {
            if (fileName.endsWith("/") || fileName.endsWith("\\")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            }
            else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            File[] children = file.listFiles();
            for (File childFile : children)
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);

            return;
        }
        FileInputStream input = new FileInputStream(file);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = input.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        input.close();
    } 

    private final void decompress (File[] files) {
        // TODO
    }
}
Michael May
  • 286
  • 2
  • 11

1 Answers1

0

After fumbling on the web, I found a tutorial on ZipOutStream, in which I noticed that the ZipOutputStream object was closed after compressing operations. So, I added code to close the ZipOutputStream object, i.e. zipOut in the compress method in my code. And the code now works properly to compress a single file, multiple files, directories, and combinations of file(s) and directory/ies.

Therefore, when using input stream and output stream object, we must remember to close them after use. Or the buffer won't get read or written properly to produce desired outcome.

I'll now continue to write the decompress method and maybe add a few more features. I may still encounter problems and I'll come here to ask for help by then. Poeple here have been very helpful and solved a lot of my questions. Thank you a lot for your help.

Thanks again for your participation.

Michael May
  • 286
  • 2
  • 11