This article shows a few examples to zip a single file and a whole directory (including sub-files and subdirectories).

  1. Zip a file – java.util.zip
  2. Zip a file – Files.copy to Zip FileSystems
  3. Zip a file on demand (without write to disk)
  4. Zip a folder – File tree and java.util.zip
  5. Zip a folder – File tree and Files.copy to Zip FileSystems
  6. zipj4 library

Java 7 introduced the Zip File System Provider, combines with Files.copy, we can copy the file attributes into the zip file easily (see example 4).

1. Zip a single file – java.util.zip

1.1 This Java example uses java.util.zip.ZipOutputStream to zip a single file.

ZipFileExample1.java

package com.favtuts.io.howto.compress;

import java.io.*;
import java.nio.file.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipFileExample {

    public static void main(String[] args) {
        
        Path source = Paths.get("/home/tvt/workspace/favtuts/Test.java");
        String zipFileName = "example.zip";

        try {
            zipSingleFile(source, zipFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // Zip a single file
    public static void zipSingleFile(Path source, String zipFileName) throws IOException {

        if (!Files.isRegularFile(source)) {
            System.err.println("Please provide a file.");
            return;
        }

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFileName));
            FileInputStream fis = new FileInputStream(source.toFile())
        ) {
            
            ZipEntry zipEntry = new ZipEntry(source.getFileName().toString());
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int len;
            while((len = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }
            zos.closeEntry();
        } 

    }
}

Output

$ unzip -l example.zip 
Archive:  example.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
     1393  2022-05-20 11:35   Test.java
---------                     -------
     1393                     1 file

$ unzip example.zip 
Archive:  example.zip
  inflating: Test.java

2. Zip a single file – FileSystems

2.1 This example uses the Java 7 NIO FileSystems.newFileSystem to create a zip file and Files.copy to copy the files into the zip path.

ZipFileExample2.java

package com.favtuts.io.howto.compress;

import java.io.*;
import java.net.URI;
import java.nio.file.*;
import java.util.*;

public class ZipFileExample {

    public static void main(String[] args) {
        
        Path source = Paths.get("/home/tvt/workspace/favtuts/Test.java");
        String zipFileName = "example.zip";

        try {
            zipSingleFileNio(source, zipFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Done");
    }

    // Zip a single file
    public static void zipSingleFileNio (Path source, String zipFileName) throws IOException {

        if (!Files.isRegularFile(source)) {
            System.err.println("Please provide a file.");
            return;
        }

        Map<String, String> env = new HashMap<>();
        // Create the zip file if it doesn't exist
        env.put("create", "true");

        URI uri = URI.create("jar:file:/home/tvt/workspace/favtuts/"+zipFileName);
        try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
            Path pathInZipfile = zipfs.getPath(source.getFileName().toString());

            // Copy a file into the zip file path
            Files.copy(source, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
        }
    }
}

3. Zip a single file on demand

This example uses ByteArrayInputStream to directly create some bytes on demand and save it into the zip file without saving or writing the data into the local file system.

package com.favtuts.io.howto.compress;

import java.io.*;
import java.net.URI;
import java.nio.file.*;
import java.util.*;
import java.util.zip.*;

public class ZipFileExample {

    public static void main(String[] args) {
              
        String zipFileName = "example.zip";

        try {       
            zipFileWithoutSaveLocal(zipFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Done");
    }
    
    // create a file on demand (without save locally) and add to zip
    public static void zipFileWithoutSaveLocal(String zipFileName) throws IOException {

        String data = "Test data \n123\n456";
        String fileNameInZip = "abc.txt";

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFileName))) {

            ZipEntry zipEntry = new ZipEntry(fileNameInZip);
            zos.putNextEntry(zipEntry);

            ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes());
            // one line, able to handle large size?
            //zos.write(bais.readAllBytes());

            // play safe
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bais.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }

            zos.closeEntry();
        }

    }
}

Output

$ unzip -l example.zip 
Archive:  example.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       18  2022-05-20 12:55   abc.txt
---------                     -------
       18                     1 file

4. Zip a folder or directory – java.util.zip

4.1 Review a directory that includes some sub-files and subdirectories.

$ tree /home/tvt/workspace/favtuts/test
test
├── data
│   └── db.debug.conf
├── file.txt
├── README.md
├── soft-link -> /home/tvt/workspace/favtuts/test/test-b/test-d/test-d2.log
├── test-a1.log
├── test-a2.log
├── test-b
│   ├── test-b1.txt
│   ├── test-b2.txt
│   ├── test-c
│   │   ├── test-c1.log
│   │   └── test-c2.log
│   └── test-d
│       ├── test-d1.log
│       └── test-d2.log
├── Test.java
└── test.log

4 directories, 14 files

4.2 This Java example uses FileVisitor to walk a file tree and ZipOutputStream to zip everything manually, including sub-files and subdirectories, but ignore symbolic links and file attributes.

ZipDirectoryExample1.java

package com.favtuts.io.howto.compress;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipDirectoryExample {

    public static void main(String[] args) {
        
        Path source = Paths.get("/home/tvt/workspace/favtuts/test");

        if (!Files.isDirectory(source)) {
            System.out.println("Please provide a folder.");
            return;
        }

        try {

            ZipDirectoryExample.zipFolder(source);

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Done");

    }

    // zip a directory, including sub files and sub directories
    public static void zipFolder(Path source) throws IOException {

        // get folder name as zip file name
        String zipFileName = source.getFileName().toString() + ".zip";

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFileName))) {
            
            Files.walkFileTree(source, new SimpleFileVisitor<>() {

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {

                    // only copy files, no symbolic links
                    if (attributes.isSymbolicLink()) {
                        return FileVisitResult.CONTINUE;
                    }

                    try (FileInputStream fis = new FileInputStream(file.toFile())) {
                        
                        Path targetFile = source.relativize(file);
                        zos.putNextEntry(new ZipEntry(targetFile.toString()));

                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = fis.read(buffer)) > 0) {
                            zos.write(buffer, 0, len);
                        }

                        // if large file, throws out of memory
                        //byte[] bytes = Files.readAllBytes(file);
                        //zos.write(bytes, 0, bytes.length);

                        zos.closeEntry();

                        System.out.printf("Zip file : %s%n", file);

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return FileVisitResult.CONTINUE;
                }


                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) {
                    System.err.printf("Unable to zip : %s%n%s%n", file, exc);
                    return FileVisitResult.CONTINUE;
                }

            });
        }
    }
    
}

Output

Zip file : /home/tvt/workspace/favtuts/test/test-a1.log
Zip file : /home/tvt/workspace/favtuts/test/data/db.debug.conf
Zip file : /home/tvt/workspace/favtuts/test/test-a2.log
Zip file : /home/tvt/workspace/favtuts/test/file.txt
Zip file : /home/tvt/workspace/favtuts/test/Test.java
Zip file : /home/tvt/workspace/favtuts/test/test.log
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-b2.txt
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-d/test-d1.log
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-d/test-d2.log
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-c/test-c2.log
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-c/test-c1.log
Zip file : /home/tvt/workspace/favtuts/test/test-b/test-b1.txt
Zip file : /home/tvt/workspace/favtuts/test/README.md
Done

The above example creates the zip file at the current working directory, and we didn’t copy the file attributes (review the file created date and time).

$ unzip -l test.zip
Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       12  2022-05-20 13:20   test-a1.log
       16  2022-05-20 13:20   data/db.debug.conf
       12  2022-05-20 13:20   test-a2.log
        9  2022-05-20 13:20   file.txt
     1393  2022-05-20 13:20   Test.java
        9  2022-05-20 13:20   test.log
       12  2022-05-20 13:20   test-b/test-b2.txt
       12  2022-05-20 13:20   test-b/test-d/test-d1.log
       12  2022-05-20 13:20   test-b/test-d/test-d2.log
       12  2022-05-20 13:20   test-b/test-c/test-c2.log
       12  2022-05-20 13:20   test-b/test-c/test-c1.log
       12  2022-05-20 13:20   test-b/test-b1.txt
       11  2022-05-20 13:20   README.md
---------                     -------
     1534                     13 files

5. Zip a folder or directory – FileSystems

5.1 This example uses the same FileVisitor to walk the file tree. Still, this time we use FileSystems URI to create the zip file, and Files.copy to copy the files into the zip path, including the file attributes, but ignore the symbolic link.

ZipDirectoryExample2.java

package com.favtuts.io.howto.compress;

import java.io.*;
import java.net.URI;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipDirectoryExample {

    public static void main(String[] args) {
        
        Path source = Paths.get("/home/tvt/workspace/favtuts/test");

        if (!Files.isDirectory(source)) {
            System.out.println("Please provide a folder.");
            return;
        }

        try {

            ZipDirectoryExample.zipFolderNio(source);

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Done");

    }

    public static void zipFolderNio(Path source) throws IOException {

        // get current working directory
        String currentPath = System.getProperty("user.dir") + File.separator;

        // get folder name as zip file name
        // can be other extension, .foo .bar .whatever
        String zipFileName = source.getFileName().toString() + ".zip";
        URI uri = URI.create("jar:file:" + currentPath + zipFileName);

        Files.walkFileTree(source, new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file,
                BasicFileAttributes attributes) {

                // Copying of symbolic links not supported
                if (attributes.isSymbolicLink()) {
                    return FileVisitResult.CONTINUE;
                }

                Map<String, String> env = new HashMap<>();
                env.put("create", "true");

                try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {

                    Path targetFile = source.relativize(file);
                    Path pathInZipfile = zipfs.getPath(targetFile.toString());

                    // NoSuchFileException, need create parent directories in zip path
                    if (pathInZipfile.getParent() != null) {
                        Files.createDirectories(pathInZipfile.getParent());
                    }

                    // copy file attributes
                    CopyOption[] options = {
                            StandardCopyOption.REPLACE_EXISTING,
                            StandardCopyOption.COPY_ATTRIBUTES,
                            LinkOption.NOFOLLOW_LINKS
                    };
                    // Copy a file into the zip file path
                    Files.copy(file, pathInZipfile, options);

                } catch (IOException e) {
                    e.printStackTrace();
                }

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                System.err.printf("Unable to zip : %s%n%s%n", file, exc);
                return FileVisitResult.CONTINUE;
            }

        });

    }
    
}

Output

$ unzip -l test.zip
Archive:  test.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       12  2022-05-17 16:43   test-a1.log
        0  2022-05-20 13:32   data/
       16  2022-05-20 13:01   data/db.debug.conf
       12  2022-05-17 16:43   test-a2.log
        9  2022-05-18 10:27   file.txt
     1393  2022-05-20 11:34   Test.java
        9  2022-05-18 22:22   test.log
        0  2022-05-20 13:32   test-b/
       12  2022-05-17 16:44   test-b/test-b2.txt
        0  2022-05-20 13:32   test-b/test-d/
       12  2022-05-17 16:45   test-b/test-d/test-d1.log
       12  2022-05-17 17:02   test-b/test-d/test-d2.log
        0  2022-05-20 13:32   test-b/test-c/
       12  2022-05-17 16:45   test-b/test-c/test-c2.log
       12  2022-05-17 16:44   test-b/test-c/test-c1.log
       12  2022-05-17 16:43   test-b/test-b1.txt
       11  2022-05-20 13:02   README.md
---------                     -------
     1534                     17 files

# unzip to an external folder abc
$ unzip test.zip -d abc
Archive:  test.zip
  inflating: abc/test-a1.log         
   creating: abc/data/
  inflating: abc/data/db.debug.conf  
  inflating: abc/test-a2.log         
  inflating: abc/file.txt            
  inflating: abc/Test.java           
  inflating: abc/test.log            
   creating: abc/test-b/
  inflating: abc/test-b/test-b2.txt  
   creating: abc/test-b/test-d/
  inflating: abc/test-b/test-d/test-d1.log  
  inflating: abc/test-b/test-d/test-d2.log  
   creating: abc/test-b/test-c/
  inflating: abc/test-b/test-c/test-c2.log  
  inflating: abc/test-b/test-c/test-c1.log  
  inflating: abc/test-b/test-b1.txt  
  inflating: abc/README.md

$ tree abc
abc
├── data
│   └── db.debug.conf
├── file.txt
├── README.md
├── test-a1.log
├── test-a2.log
├── test-b
│   ├── test-b1.txt
│   ├── test-b2.txt
│   ├── test-c
│   │   ├── test-c1.log
│   │   └── test-c2.log
│   └── test-d
│       ├── test-d1.log
│       └── test-d2.log
├── Test.java
└── test.log

4 directories, 13 files

6. Zip file – zip4j

The zip4j is a popular zip library in Java; it has many advanced features like a password-protected zip file, split zip file, AES encryption, etc. Please visit the zip4j github for further documentation and usages.

Here’s are some common usages to zip files and folder.

import net.lingala.zip4j.ZipFile;

//...
  public static void zip4j() throws IOException {

      // zip file with a single file
      new ZipFile("filename.zip").addFile("file.txt");

      // zip file with multiple files
      List<File> files = Arrays.asList(
              new File("file1.txt"), new File("file2.txt"));
      new ZipFile("filename.zip").addFiles(files);

      // zip file with a folder
      new ZipFile("filename.zip").addFolder(new File("/home/favtuts/folder"));


  }

Further Reading

How to unzip a zip file in Java

Download Source Code

$ git clone https://github.com/favtuts/java-core-tutorials-examples

$ cd java-io/howto/compress

References

Leave a Reply

Your email address will not be published. Required fields are marked *