What is a good Java library to zip/unzip files?

CompressionZipUnzipJava

Compression Problem Overview


I looked at the default Zip library that comes with the JDK and the Apache compression libs and I am unhappy with them for 3 reasons:

  1. They are bloated and have bad API design. I have to write 50 lines of boiler plate byte array output, zip input, file out streams and close relevant streams and catch exceptions and move byte buffers on my own? Why can't I have a simple API that looks like this Zipper.unzip(InputStream zipFile, File targetDirectory, String password = null) and Zipper.zip(File targetDirectory, String password = null) that just works?

  2. It seems zipping unzipping destroys file meta-data and password handling is broken.

  3. Also, all the libraries I tried were 2-3x slow compared to the command line zip tools I get with UNIX?

For me (2) and (3) are minor points but I really want a good tested library with a one-line interface.

Compression Solutions


Solution 1 - Compression

I know its late and there are lots of answers but this zip4j is one of the best libraries for zipping I have used. Its simple (no boiler code) and can easily handle password protected files.

import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.core.ZipFile;


public static void unzip(){
    String source = "some/compressed/file.zip";
    String destination = "some/destination/folder";
    String password = "password";

    try {
         ZipFile zipFile = new ZipFile(source);
         if (zipFile.isEncrypted()) {
            zipFile.setPassword(password);
         }
         zipFile.extractAll(destination);
    } catch (ZipException e) {
        e.printStackTrace();
    }
}

The Maven dependency is:

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>1.3.2</version>
</dependency>

Solution 2 - Compression

In Java 8, with Apache Commons-IO's IOUtils you can do this:

try (java.util.zip.ZipFile zipFile = new ZipFile(file)) {
  Enumeration<? extends ZipEntry> entries = zipFile.entries();
  while (entries.hasMoreElements()) {
    ZipEntry entry = entries.nextElement();
    File entryDestination = new File(outputDir,  entry.getName());
    if (entry.isDirectory()) {
        entryDestination.mkdirs();
    } else {
        entryDestination.getParentFile().mkdirs();
        try (InputStream in = zipFile.getInputStream(entry);
             OutputStream out = new FileOutputStream(entryDestination)) {
            IOUtils.copy(in, out);
        }
    }
  }
}

It's still some boilerplate code, but it has only 1 non-exotic dependency: Commons-IO

In Java 11 and higher, better options might be available, see ZhekaKozlov's comment.

Solution 3 - Compression

Extract zip file and all its subfolders, using only the JDK:

private void extractFolder(String zipFile,String extractFolder) 
{
    try
    {
        int BUFFER = 2048;
        File file = new File(zipFile);

        ZipFile zip = new ZipFile(file);
        String newPath = extractFolder;

        new File(newPath).mkdir();
        Enumeration zipFileEntries = zip.entries();

        // Process each entry
        while (zipFileEntries.hasMoreElements())
        {
            // grab a zip file entry
            ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
            String currentEntry = entry.getName();
            
            File destFile = new File(newPath, currentEntry);
            //destFile = new File(newPath, destFile.getName());
            File destinationParent = destFile.getParentFile();

            // create the parent directory structure if needed
            destinationParent.mkdirs();

            if (!entry.isDirectory())
            {
                BufferedInputStream is = new BufferedInputStream(zip
                .getInputStream(entry));
                int currentByte;
                // establish buffer for writing file
                byte data[] = new byte[BUFFER];

                // write the current file to disk
                FileOutputStream fos = new FileOutputStream(destFile);
                BufferedOutputStream dest = new BufferedOutputStream(fos,
                BUFFER);

                // read and write until last byte is encountered
                while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
                    dest.write(data, 0, currentByte);
                }
                dest.flush();
                dest.close();
                is.close();
            }


        }
    }
    catch (Exception e) 
    {
        Log("ERROR: "+e.getMessage());
    }
    
}

Zip files and all its subfolders:

 private void addFolderToZip(File folder, ZipOutputStream zip, String baseName) throws IOException {
	File[] files = folder.listFiles();
	for (File file : files) {
		if (file.isDirectory()) {
			addFolderToZip(file, zip, baseName);
		} else {
			String name = file.getAbsolutePath().substring(baseName.length());
			ZipEntry zipEntry = new ZipEntry(name);
			zip.putNextEntry(zipEntry);
			IOUtils.copy(new FileInputStream(file), zip);
			zip.closeEntry();
		}
	}
}

Solution 4 - Compression

Another option that you can check out is zt-zip available from Maven central and project page at https://github.com/zeroturnaround/zt-zip

It has the standard packing and unpacking functionality (on streams and on filesystem) + lots of helper methods to test for files in an archive or add/remove entries.

Solution 5 - Compression

Full Implementation to Zip/Unzip a Folder/File with zip4j


Add this dependency to your build manager. Or, download the latest JAR file from here and add it to your project build path. The class bellow can compress and extract any file or folder with or without password protection-

import java.io.File;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import net.lingala.zip4j.core.ZipFile;	

public class Compressor {
    public static void zip (String targetPath, String destinationFilePath, String password) {
        try {
            ZipParameters parameters = new ZipParameters();
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

            if (password.length() > 0) {
                parameters.setEncryptFiles(true);
                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
                parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
                parameters.setPassword(password);
            }
				
            ZipFile zipFile = new ZipFile(destinationFilePath);
				
            File targetFile = new File(targetPath);
            if (targetFile.isFile()) {
                zipFile.addFile(targetFile, parameters);
            } else if (targetFile.isDirectory()) {
                zipFile.addFolder(targetFile, parameters);
            } else {
                //neither file nor directory
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	    
    public static void unzip(String targetZipFilePath, String destinationFolderPath, String password) {
        try {
            ZipFile zipFile = new ZipFile(targetZipFilePath);
            if (zipFile.isEncrypted()) {
                zipFile.setPassword(password);
            }
            zipFile.extractAll(destinationFolderPath);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**/ /// for test
    public static void main(String[] args) {
        
        String targetPath = "target\\file\\or\\folder\\path";
        String zipFilePath = "zip\\file\\Path"; 
        String unzippedFolderPath = "destination\\folder\\path";
        String password = "your_password"; // keep it EMPTY<""> for applying no password protection
			
        Compressor.zip(targetPath, zipFilePath, password);
        Compressor.unzip(zipFilePath, unzippedFolderPath, password);
    }/**/
}

For more detailed usage, please see here.

Solution 6 - Compression

A very nice project is TrueZip.

> TrueZIP is a Java based plug-in framework for virtual file systems (VFS) which provides transparent access to archive files as if they were just plain directories

For example (from the website):

File file = new TFile("archive.tar.gz/README.TXT");
OutputStream out = new TFileOutputStream(file);
try {
   // Write archive entry contents here.
   ...
} finally {
   out.close();
}

Solution 7 - Compression

Another option is JZlib. In my experience, it's less "file-centered" than zip4J, so if you need to work on in-memory blobs rather than files, you may want to take a look at it.

Solution 8 - Compression

Did you have a look at http://commons.apache.org/vfs/ ? It claims to simplify a lot of things for you. But I've never used it in a project.

I also am not aware of Java-Native compression libs other than the JDK or Apache Compression.

I remember once we ripped some features out of Apache Ant - they have a lot of utils for compression / decompression built in.

Sample code with VFS would look like:

File zipFile = ...;
File outputDir = ...;
FileSystemManager fsm = VFS.getManager();
URI zip = zipFile.toURI();
FileObject packFileObject = fsm.resolveFile(packLocation.toString());
FileObject to = fsm.toFileObject(destDir);
FileObject zipFS;
try {
    zipFS = fsm.createFileSystem(packFileObject);
    fsm.toFileObject(outputDir).copyFrom(zipFS, new AllFileSelector());
} finally {
    zipFS.close();
}

Solution 9 - Compression

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpathikritView Question on Stackoverflow
Solution 1 - Compressionuser2003470View Answer on Stackoverflow
Solution 2 - CompressionGeoffrey De SmetView Answer on Stackoverflow
Solution 3 - CompressionBashir BeikzadehView Answer on Stackoverflow
Solution 4 - CompressiontoomasrView Answer on Stackoverflow
Solution 5 - CompressionMinhas KamalView Answer on Stackoverflow
Solution 6 - CompressionMichaelView Answer on Stackoverflow
Solution 7 - CompressionHenrik Aasted SørensenView Answer on Stackoverflow
Solution 8 - CompressionwemuView Answer on Stackoverflow
Solution 9 - Compressionuser1491819View Answer on Stackoverflow