72
votes

Suppose I have the following directory structure.

D:\reports\january\

Inside january there are suppose two excel files say A.xls and B.xls. There are many places where it has been written about how to zip files using java.util.zip. But I want to zip the january folder itself inside reports folder so that both january and january.zip will be present inside reports. (That means when I unzip the january.zip file I should get the january folder).

Can anyone please provide me the code to do this using java.util.zip. Please let me know whether this can be more easily done by using other libraries.

Thanks a lot...

16
Why moderators don't close this kind of questions, it directly against rules from the first page "Don't ask about... Questions you haven't tried to find an answer for (show your work!)".CheatEx

16 Answers

100
votes

Have you tried Zeroturnaround Zip library? It's really neat! Zip a folder is just a one liner:

ZipUtil.pack(new File("D:\\reports\\january\\"), new File("D:\\reports\\january.zip"));

(thanks to Oleg Šelajev for the example)

90
votes

Here is the Java 8+ example:

public static void pack(String sourceDirPath, String zipFilePath) throws IOException {
    Path p = Files.createFile(Paths.get(zipFilePath));
    try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p))) {
        Path pp = Paths.get(sourceDirPath);
        Files.walk(pp)
          .filter(path -> !Files.isDirectory(path))
          .forEach(path -> {
              ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString());
              try {
                  zs.putNextEntry(zipEntry);
                  Files.copy(path, zs);
                  zs.closeEntry();
            } catch (IOException e) {
                System.err.println(e);
            }
          });
    }
}
69
votes

It can be easily solved by package java.util.Zip no need any extra Jar files

Just copy the following code and run it with your IDE

//Import all needed packages
package general;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipUtils {

    private List <String> fileList;
    private static final String OUTPUT_ZIP_FILE = "Folder.zip";
    private static final String SOURCE_FOLDER = "D:\\Reports"; // SourceFolder path

    public ZipUtils() {
        fileList = new ArrayList < String > ();
    }

    public static void main(String[] args) {
        ZipUtils appZip = new ZipUtils();
        appZip.generateFileList(new File(SOURCE_FOLDER));
        appZip.zipIt(OUTPUT_ZIP_FILE);
    }

    public void zipIt(String zipFile) {
        byte[] buffer = new byte[1024];
        String source = new File(SOURCE_FOLDER).getName();
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        try {
            fos = new FileOutputStream(zipFile);
            zos = new ZipOutputStream(fos);

            System.out.println("Output to Zip : " + zipFile);
            FileInputStream in = null;

            for (String file: this.fileList) {
                System.out.println("File Added : " + file);
                ZipEntry ze = new ZipEntry(source + File.separator + file);
                zos.putNextEntry(ze);
                try {
                    in = new FileInputStream(SOURCE_FOLDER + File.separator + file);
                    int len;
                    while ((len = in .read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                } finally {
                    in.close();
                }
            }

            zos.closeEntry();
            System.out.println("Folder successfully compressed");

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                zos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void generateFileList(File node) {
        // add file only
        if (node.isFile()) {
            fileList.add(generateZipEntry(node.toString()));
        }

        if (node.isDirectory()) {
            String[] subNote = node.list();
            for (String filename: subNote) {
                generateFileList(new File(node, filename));
            }
        }
    }

    private String generateZipEntry(String file) {
        return file.substring(SOURCE_FOLDER.length() + 1, file.length());
    }
}

Refer mkyong..I changed the code for the requirement of current question

34
votes

Here's a pretty terse Java 7+ solution which relies purely on vanilla JDK classes, no third party libraries required:

public static void pack(final Path folder, final Path zipFilePath) throws IOException {
    try (
            FileOutputStream fos = new FileOutputStream(zipFilePath.toFile());
            ZipOutputStream zos = new ZipOutputStream(fos)
    ) {
        Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                zos.putNextEntry(new ZipEntry(folder.relativize(file).toString()));
                Files.copy(file, zos);
                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }

            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                zos.putNextEntry(new ZipEntry(folder.relativize(dir).toString() + "/"));
                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }
        });
    }
}

It copies all files in folder, including empty directories, and creates a zip archive at zipFilePath.

13
votes

Java 7+, commons.io

public final class ZipUtils {

    public static void zipFolder(final File folder, final File zipFile) throws IOException {
        zipFolder(folder, new FileOutputStream(zipFile));
    }

    public static void zipFolder(final File folder, final OutputStream outputStream) throws IOException {
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
            processFolder(folder, zipOutputStream, folder.getPath().length() + 1);
        }
    }

    private static void processFolder(final File folder, final ZipOutputStream zipOutputStream, final int prefixLength)
            throws IOException {
        for (final File file : folder.listFiles()) {
            if (file.isFile()) {
                final ZipEntry zipEntry = new ZipEntry(file.getPath().substring(prefixLength));
                zipOutputStream.putNextEntry(zipEntry);
                try (FileInputStream inputStream = new FileInputStream(file)) {
                    IOUtils.copy(inputStream, zipOutputStream);
                }
                zipOutputStream.closeEntry();
            } else if (file.isDirectory()) {
                processFolder(file, zipOutputStream, prefixLength);
            }
        }
    }
}
9
votes

I usually use a helper class I once wrote for this task:

import java.util.zip.*;
import java.io.*;

public class ZipExample {
    public static void main(String[] args){
        ZipHelper zippy = new ZipHelper();
        try {
            zippy.zipDir("folderName","test.zip");
        } catch(IOException e2) {
            System.err.println(e2);
        }
    }
}

class ZipHelper  
{
    public void zipDir(String dirName, String nameZipFile) throws IOException {
        ZipOutputStream zip = null;
        FileOutputStream fW = null;
        fW = new FileOutputStream(nameZipFile);
        zip = new ZipOutputStream(fW);
        addFolderToZip("", dirName, zip);
        zip.close();
        fW.close();
    }

    private void addFolderToZip(String path, String srcFolder, ZipOutputStream zip) throws IOException {
        File folder = new File(srcFolder);
        if (folder.list().length == 0) {
            addFileToZip(path , srcFolder, zip, true);
        }
        else {
            for (String fileName : folder.list()) {
                if (path.equals("")) {
                    addFileToZip(folder.getName(), srcFolder + "/" + fileName, zip, false);
                } 
                else {
                     addFileToZip(path + "/" + folder.getName(), srcFolder + "/" + fileName, zip, false);
                }
            }
        }
    }

    private void addFileToZip(String path, String srcFile, ZipOutputStream zip, boolean flag) throws IOException {
        File folder = new File(srcFile);
        if (flag) {
            zip.putNextEntry(new ZipEntry(path + "/" +folder.getName() + "/"));
        }
        else {
            if (folder.isDirectory()) {
                addFolderToZip(path, srcFile, zip);
            }
            else {
                byte[] buf = new byte[1024];
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                zip.putNextEntry(new ZipEntry(path + "/" + folder.getName()));
                while ((len = in.read(buf)) > 0) {
                    zip.write(buf, 0, len);
                }
            }
        }
    }
}
9
votes

Enhanced Java 8+ example (Forked from Nikita Koksharov's answer)

public static void pack(String sourceDirPath, String zipFilePath) throws IOException {
    Path p = Files.createFile(Paths.get(zipFilePath));
    Path pp = Paths.get(sourceDirPath);
    try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p));
        Stream<Path> paths = Files.walk(pp)) {
        paths
          .filter(path -> !Files.isDirectory(path))
          .forEach(path -> {
              ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString());
              try {
                  zs.putNextEntry(zipEntry);
                  Files.copy(path, zs);
                  zs.closeEntry();
            } catch (IOException e) {
                System.err.println(e);
            }
          });
    }
}

Files.walk has been wrapped in try with resources block so that stream can be closed. This resolves blocker issue identified by SonarQube. Thanks @Matt Harrison for pointing this.

4
votes

I would use Apache Ant, which has an API to call tasks from Java code rather than from an XML build file.

Project p = new Project();
p.init();
Zip zip = new Zip();
zip.setProject(p);
zip.setDestFile(zipFile); // a java.io.File for the zip you want to create
zip.setBasedir(new File("D:\\reports"));
zip.setIncludes("january/**");
zip.perform();

Here I'm telling it to start from the base directory D:\reports and zip up the january folder and everything inside it. The paths in the resulting zip file will be the same as the original paths relative to D:\reports, so they will include the january prefix.

2
votes

Try this:

 import java.io.File;

 import java.io.FileInputStream;

 import java.io.FileOutputStream;

 import java.util.zip.ZipEntry;

 import java.util.zip.ZipOutputStream;


  public class Zip {

public static void main(String[] a) throws Exception {

    zipFolder("D:\\reports\\january", "D:\\reports\\january.zip");

  }

  static public void zipFolder(String srcFolder, String destZipFile) throws Exception {
    ZipOutputStream zip = null;
    FileOutputStream fileWriter = null;
    fileWriter = new FileOutputStream(destZipFile);
    zip = new ZipOutputStream(fileWriter);
    addFolderToZip("", srcFolder, zip);
    zip.flush();
    zip.close();
  }
  static private void addFileToZip(String path, String srcFile, ZipOutputStream zip)
      throws Exception {
    File folder = new File(srcFile);
    if (folder.isDirectory()) {
      addFolderToZip(path, srcFile, zip);
    } else {
      byte[] buf = new byte[1024];
      int len;
      FileInputStream in = new FileInputStream(srcFile);
      zip.putNextEntry(new ZipEntry(path + "/" + folder.getName()));
      while ((len = in.read(buf)) > 0) {
        zip.write(buf, 0, len);
      }
    }
  }

  static private void addFolderToZip(String path, String srcFolder, ZipOutputStream zip)
      throws Exception {
    File folder = new File(srcFolder);

    for (String fileName : folder.list()) {
      if (path.equals("")) {
        addFileToZip(folder.getName(), srcFolder + "/" + fileName, zip);
      } else {
        addFileToZip(path + "/" + folder.getName(), srcFolder + "/" +   fileName, zip);
      }
    }
  }



   }
2
votes

Using zip4j you can simply do this

ZipFile zipfile = new ZipFile(new File("D:\\reports\\january\\filename.zip"));
zipfile.addFolder(new File("D:\\reports\\january\\"));

It will archive your folder and everything in it.

Use the .extractAll method to get it all out:

zipfile.extractAll("D:\\destination_directory");
1
votes

Java 6 +

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

public class Zip {

    private static final FileFilter FOLDER_FILTER = new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.isDirectory();
        }
    };

    private static final FileFilter FILE_FILTER = new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            return pathname.isFile();
        }
    };


    private static void compress(File file, ZipOutputStream outputStream, String path) throws IOException {

        if (file.isDirectory()) {
            File[] subFiles = file.listFiles(FILE_FILTER);
            if (subFiles != null) {
                for (File subFile : subFiles) {
                    compress(subFile, outputStream, new File(path, subFile.getName()).getAbsolutePath());
                }
            }
            File[] subDirs = file.listFiles(FOLDER_FILTER);
            if (subDirs != null) {
                for (File subDir : subDirs) {
                    compress(subDir, outputStream, new File(path, subDir.getName()).getAbsolutePath());
                }
            }
        } else if (file.exists()) {
            outputStream.putNextEntry(new ZipEntry(path));
            FileInputStream inputStream = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) >= 0) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.closeEntry();
        }
    }

    public static void compress(String dirPath, String zipFilePath) throws IOException {
        File file = new File(dirPath);
        final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFilePath));
        compress(file, outputStream, "/");
        outputStream.close();
    }

}
1
votes

I found this solution worked perfectly fine for me. Doesn't require any third party apis

'test' is actually a folder will lots of file inside.

String folderPath= "C:\Users\Desktop\test";
String zipPath = "C:\Users\Desktop\test1.zip";

private boolean zipDirectory(String folderPath, String zipPath) throws IOException{

        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        ZipOutputStream zos = null;

        try{
            zos = new ZipOutputStream(new FileOutputStream(zipPath));
            updateSourceFolder(new File(folderPath));

            if (sourceFolder == null) {
                zos.close();
                return false;
            }
            generateFileAndFolderList(new File(folderPath));

            for (String unzippedFile: fileList) {
                System.out.println(sourceFolder + unzippedFile);

                ZipEntry entry = new ZipEntry(unzippedFile);
                zos.putNextEntry(entry);

                if ((unzippedFile.substring(unzippedFile.length()-1)).equals(File.separator))
                    continue;
                try{
                    fis = new FileInputStream(sourceFolder + unzippedFile);
                    int len=0;
                    while ((len = fis.read(buffer))>0) {
                        zos.write(buffer,0,len);
                    }
                } catch(IOException e) {
                    return false;
                } finally {
                    if (fis != null)
                        fis.close();
                }
            }
            zos.closeEntry();
        } catch(IOException e) {
            return false;
        } finally {
            zos.close();
            fileList = null;
            sourceFolder = null;
        }
        return true;
    }

    private void generateFileAndFolderList(File node) {
        if (node.isFile()) {
            fileList.add(generateZipEntry(node.getAbsoluteFile().toString()));
        }
        if (node.isDirectory()) {
            String dir = node.getAbsoluteFile().toString();
            fileList.add(dir.substring(sourceFolder.length(), dir.length()) + File.separator);

            String[] subNode = node.list();
            for (String fileOrFolderName : subNode) {
                generateFileAndFolderList(new File(node, fileOrFolderName));
            }
        }
    }

    private void updateSourceFolder(File node) {
        if (node.isFile() || node.isDirectory()) {
            String sf = node.getAbsoluteFile().toString();
            sourceFolder = sf.substring(0, (sf.lastIndexOf("/") > 0 ? sf.lastIndexOf("/") : sf.lastIndexOf("\\")));
            sourceFolder += File.separator;
        } else
            sourceFolder = null;
    }

    private String generateZipEntry(String file) {
        return file.substring(sourceFolder.length(), file.length());
    }
1
votes

This method zips a folder and adds all of the child files & folders (including empty folders) into the zip file.

void zipFolder(Path sourceDir, Path targetFile) throws IOException {
    ZipDirectoryVisitor zipVisitor = new ZipDirectoryVisitor(sourceDir);
    Files.walkFileTree(sourceDir, zipVisitor);
    FileOutputStream fos = new FileOutputStream(targetFile.toString());
    ZipOutputStream zos = new ZipOutputStream(fos);
    byte[] buffer = new byte[1024];
    for (ZipEntry entry : zipVisitor.getZipEntries()) {
        zos.putNextEntry(entry);
        Path curFile = Paths.get(sourceDir.getParent().toString(), entry.toString());
        if (!curFile.toFile().isDirectory()) {
            FileInputStream in = new FileInputStream(Paths.get(sourceDir.getParent().toString(), entry.toString()).toString());
            int len;
            while ((len = in.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }
            in.close();
        }
        zos.closeEntry();
    }
    zos.close();

}

And here is the ZipDirectoryVisitor implementation:

class ZipDirectoryVisitor extends SimpleFileVisitor<Path> {
    private Path dirToZip;
    private List<ZipEntry> zipEntries; // files and folders inside source folder as zip entries
    public ZipDirectoryVisitor(Path dirToZip) throws IOException {
        this.dirToZip = dirToZip;
        zipEntries = new ArrayList<>();
    }

    @Override
    public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException {
        // According to zip standard backslashes
        // should not be used in zip entries
        String zipFile = dirToZip.getParent().relativize(path).toString().replace("\\", "/");
        ZipEntry entry = new ZipEntry(zipFile);
        zipEntries.add(entry);
        return FileVisitResult.CONTINUE;
    }


    @Override
    public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes basicFileAttributes) throws IOException {
        String zipDir = dirToZip.getParent().relativize(path).toString().replace("\\", "/");
        // Zip directory entries should end with a forward slash
        ZipEntry entry = new ZipEntry(zipDir + "/");
        zipEntries.add(entry);
        return FileVisitResult.CONTINUE;
    }


    @Override
    public FileVisitResult visitFileFailed(Path path, IOException e) throws IOException {
        System.err.format("Could not visit file %s while creating a file list from file tree", path);
        return FileVisitResult.TERMINATE;
    }

    public List<ZipEntry> getZipEntries() {
        return zipEntries;
    }
}
0
votes

I have modified the above solutions and replaced Files.walk with Files.list. This also assumes the directory you are zipping only contains file and not any sub directories.

private void zipDirectory(Path dirPath) throws IOException {
        String zipFilePathStr = dirPath.toString() + ".zip";
        Path zipFilePath = Files.createFile(Paths.get(zipFilePathStr));

        try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(zipFilePath))) {
            Files.list(dirPath)
                .filter(filePath-> !Files.isDirectory(filePath))
                .forEach(filePath-> {
                    ZipEntry zipEntry = new ZipEntry(dirPath.relativize(filePath).toString());
                    try {
                        zs.putNextEntry(zipEntry);
                        Files.copy(filePath, zs);
                        zs.closeEntry();
                    }
                    catch (IOException e) {
                        System.err.println(e);
                    }
                });
        }
    }
0
votes

Improving @Nikita Koksharov's code had problems packing empty directories.

private void zipDirectory(OutputStream outputStream, Path directoryPath) throws IOException {
    try (ZipOutputStream zs = new ZipOutputStream(outputStream)) {
        Path pp = directoryPath;
        Files.walk(pp)
                .forEach(path -> {
                    try {
                        if (Files.isDirectory(path)) {
                            zs.putNextEntry(new ZipEntry(pp.relativize(path).toString() + "/"));
                        } else {
                            ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString());
                            zs.putNextEntry(zipEntry);
                            Files.copy(path, zs);
                            zs.closeEntry();
                        }
                    } catch (IOException e) {
                        System.err.println(e);
                    }
                });
    }
}

Test usage

    FileOutputStream zipOutput = new FileOutputStream("path_to_file.zip");
    Path pathOutput = Path.of("path_directory_fid");
    zipDirectory(outputStream, pathOutput);
0
votes

try this zip("C:\testFolder", "D:\testZip.zip")

public void zip( String sourcDirPath,  String zipPath) throws IOException {
  Path zipFile = Files.createFile(Paths.get(zipPath));

  Path sourceDirPath = Paths.get(sourcDirPath);
  try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile));
       Stream<Path> paths = Files.walk(sourceDirPath)) {
      paths
              .filter(path -> !Files.isDirectory(path))
              .forEach(path -> {
                  ZipEntry zipEntry = new ZipEntry(sourceDirPath.relativize(path).toString());
                  try {
                      zipOutputStream.putNextEntry(zipEntry);
                      Files.copy(path, zipOutputStream);
                      zipOutputStream.closeEntry();
                  } catch (IOException e) {
                      System.err.println(e);
                  }
              });
  }

  System.out.println("Zip is created at : "+zipFile);
}