How to Create and Update Zip File in Java

In this tutorial, we’ll explore how to easily create ZIP files, including multiple files, multiple directories, and updating an existing ZIP file in Java.

Table of Contents:

1. Import Necessary Classes

We use the built-in Java utility classes for creating ZIP files:


import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
import java.util.stream.Stream;

2. Creating a ZIP with Multiple Files and Directories

Here’s how we can compress multiple files and directories:

JavaZipExample.java

package com.mkyong.zip;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class JavaZipExample {

    public static void main(String[] args) {
        String[] files = {"file1.txt", "file2.txt"};
        String[] directories = {"folder1", "folder2"};
        String zipFile = "files.zip";

        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            // Adding files
            for (String file : files) {
                Path filePath = Paths.get(file);
                if (!Files.exists(filePath)) {
                    throw new FileNotFoundException("File does not exists: " + filePath);
                }
                addToZipFile(filePath, zos);
            }

            // Adding directories
            for (String dir : directories) {
                Path dirPath = Paths.get(dir);
                if (!Files.exists(dirPath) || !Files.isDirectory(dirPath)) {
                    throw new IOException("Directory does not exist: " + dirPath);
                }
                try (Stream<Path> paths = Files.walk(dirPath)) {
                    paths.filter(path -> !Files.isDirectory(path))
                            .forEach(path -> addToZipFile(path, zos));
                }
            }

            System.out.println("ZIP file created successfully!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void addToZipFile(Path file, ZipOutputStream zos) {
        try (FileInputStream fis = new FileInputStream(file.toFile())) {
            // Replace backslashes with forward slashes for compatibility
            String zipEntryName = file.toString().replace("\\", "/");
            zos.putNextEntry(new ZipEntry(zipEntryName));

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }
            zos.closeEntry();
        } catch (IOException e) {
            System.err.println("Failed to zip file: " + file);
            e.printStackTrace();
        }
    }

}

The line file.toString().replace("\\", "/") ensures compatibility with ZIP file standards, which use forward slashes (/) as path separators. Java typically returns file paths with backslashes (\) on Windows. Replacing backslashes prevents issues when the ZIP file is extracted on other operating systems such as Linux or macOS.

3. Adding Files or Directories to an Existing ZIP File

To add new files or directories into an existing ZIP file, use this source code:

JavaAddToExistingZip.java

package com.mkyong.zip;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class JavaAddToExistingZip {

    private static void addToZipFile(Path file, ZipOutputStream zos) {
        try (FileInputStream fis = new FileInputStream(file.toFile())) {
            // Replace backslashes with forward slashes for compatibility
            String zipEntryName = file.toString().replace("\\", "/");
            zos.putNextEntry(new ZipEntry(zipEntryName));

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }
            zos.closeEntry();
        } catch (IOException e) {
            System.err.println("Failed to zip file: " + file);
            e.printStackTrace();
        }
    }

    public static void addToExistingZip(String existingZipPath, String newPath) throws IOException {
        Path zipPath = Paths.get(existingZipPath);
        if (!Files.exists(zipPath)) {
            throw new IOException("ZIP file does not exist: " + existingZipPath);
        }

        Path tempZip = Files.createTempFile(null, null);

        try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(tempZip));
             ZipInputStream zis = new ZipInputStream(new FileInputStream(existingZipPath))) {

            ZipEntry entry;
            byte[] buffer = new byte[1024];

            // Copy existing ZIP entries to tempZip 
            while ((entry = zis.getNextEntry()) != null) {
                zos.putNextEntry(new ZipEntry(entry.getName()));
                int len;
                while ((len = zis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
                zos.closeEntry();
            }

            // Check if path is file or directory
            Path newPathObj = Paths.get(newPath);
            if (Files.isDirectory(newPathObj)) {
                try (Stream<Path> paths = Files.walk(newPathObj)) {
                    paths.filter(path -> !Files.isDirectory(path))
                            .forEach(path -> addToZipFile(path, zos));
                }
            } else {
                addToZipFile(newPathObj, zos);
            }
        }

        // Replace original ZIP with updated ZIP (tempZip)
        Files.move(tempZip, Paths.get(existingZipPath), StandardCopyOption.REPLACE_EXISTING);
    }

    public static void main(String[] args) throws IOException {

        String file = "newfile.txt";
        //String file = "newfolder";
        String zipFile = "existingfiles.zip";

        addToExistingZip(zipFile, file);

    }
}

4. References

mkyong

Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities.

34 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Petros
5 years ago

Is there a way to create multiple txt files (without creating the txt files locally) which will be zipped and then send back to the user as a zipped folder? I have created a web service which enables the user to download a zipped folder with specific txt files. But in order to do that, I have to create the txt files locally -> zip them -> delete the txt files from the local storage.

When the service is deployed, I am not allowed to create files on the server. I saw that some people mentioned to create the files in-memory but there are risks. There is a case that I might run out of memory.

private File writeToFile(String lines, String fileName, File directoryName) throws IOException {

		File file = new File(directoryName, fileName);

		BufferedWriter writer = new BufferedWriter(new FileWriter(file));
		writer.write(lines);

		writer.close();
		return file;
	}

The above method is used to create and return a File. I have a List<File> which contains all the txt files. I iterate the list and add the files into ZipOutputStream etc.

What do you think I should do? Is there an example which I can see?

Petros
5 years ago
Reply to  mkyong

I managed to find a solution using the combination of example 3 and my code. The website does not allow me to delete my old comments in order to upload the code.

Petros
5 years ago
Reply to  mkyong

The code on example 3 did not work for me when I used Postman to send a GET request (selected Send and Download).

I used your code as like this:

	@GetMapping("/test")
	public void test() throws IOException {
		reportService.testZipCreation();
	}
	public void testZipCreation() throws IOException {
		zipFileWithoutSaveLocal("testZipCreation.zip");
	}
// create a file on demand (without save locally) and add to zip
	private 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();
	    }

	}

When I send a request from Postman, I was getting an empty txt file called response.txt.

Maybe I did something incorrectly.

Last edited 5 years ago by Petros
Petros
5 years ago
Reply to  Petros

I had to make a modification by providing an HttpServletResponse as an argument.

Following, you can view the modifications:

@GetMapping("/testV2")
	public void testV2(HttpServletResponse response) throws IOException {
		reportService.testZipCreationV2(response);
	}
public void testZipCreationV2(HttpServletResponse response) throws IOException {
		
		response.setContentType("application/octet-stream");
		response.setHeader("Content-Disposition", "attachment;filename=testZipCreationV2.zip");
		response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
		response.setStatus(HttpServletResponse.SC_OK);
		
		zipFileWithoutSaveLocalV2(response);
	}
// create a file on demand (without save locally) and add to zip
	private void zipFileWithoutSaveLocalV2(HttpServletResponse response) throws IOException {

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

	    try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {

	        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();
	    }
	}

I have to create a method that zips multiple txt files with different txt names.

Petros
5 years ago
Reply to  mkyong

Thank you very much for your help!

Hannes S
8 years ago

“great” example…Sry, but this example creates invalid ZIP files. Within ZIP files you should ALWAYS use forward slashes for paths – this is described within the ZIP standard (https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT). this example creates backward slashes for paths on windows file systems. I wouldn’t blame you, if you were using unix, but obviously you ARE using windows.
Please adapt this to avoid others creating invalid ZIPs.

Koushik Roy (bOyInDBoX)
11 years ago

I have a requirement to zip an XML file generated in the same code flow. I am marshalling a java object to outputstream. But I don’t want to write the XML file. Because all I need is the zip file, XML file is not being used later.

I was trying to discover if we can directly zip the outputstream of xml into a zip file without creating the intermediate XML file.

My last option would be, creating the XML file, then creating the ZIP file from it and then deleting the XML file.

Please let me know if this is possible.

varun
8 years ago

Hi did you get the code? if you can you please share the code i am also facing the same problem please hep.

Andrew
13 years ago

Thank You

Oliver Yao
4 years ago

Hi,
just see your zip example here. it seems zip folder examples always zip the files and sub-folder, not include the starting folder itself. That seems different from standard tool like zip4j.
For example, you zip folder: test, but test is not in the zip file, only files and sub-folder under test are zipped. I could be wrong though.
Thanks,
Oliver Yao

Mohini Chaudhari
5 years ago

Hi mkyong thank you for this example 5.Zip a folder or directory -FileSystems
It’s working fine on linux but not on windows.

Aaron
5 years ago

What about zip4jvm. Looks like it has more comressions and encryption methods. And pretty comfortable to use.
https://github.com/oleg-cherednik/zip4jvm

pp.
5 years ago

Hello Mkyong,
thanks for the example. Just one improvement:

FileOutputStream fos = new FileOutputStream(zipFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);

Wrapping the FileOutputStream into a BufferedOutputStream will make zip-file creation MUCH faster.

Sahil
7 years ago

how to preserve file permissions with zip creation?

Sarthak
8 years ago

How can I create self Extract executable file using java ? any idea.

Joseph Selvaraj
10 years ago

Hi Kong, I tested this code , In last line “SOURCE_FOLDER.length()+1 ” , +1 is not required. Am I right?

Mohammad
12 years ago

Hi, thank you a lot, But It Has A Problem!!!
if we get it an empty folder, it will throw exception, and also, if we have an empty folder in another folder, it doesn’t create that empty folder!

Hannes S
7 years ago
Reply to  Mohammad

Zip does not contain folders as such, but only files. Thus empty folders won’t be possible with zip.

Praveen
12 years ago

Hello Sir,
I have a requirement where client can download all uploaded file from server.
I have done downloading for single file. But i am not able to allow user to download all file at a single click
Please Help me with this. all files are image file and i am suppose to zip it and allow download to user pc.
Thank you
Praveen

Mohammed Amine
12 years ago

Hi mkyong thank you for this section it is interesting but the code does not work it gives an empty archive 🙁

YoYo
13 years ago

If i have a list of files, and i would like to rename it beofre zip it up, how could that be done?Can anyone advise? Many Thanks.

Pankaj
13 years ago

The closeEntry() call should be inside the for loop in compressing directory.

site
14 years ago

The design for the blog is a tad off in Epiphany. Nevertheless I like your website. I may need to use a normal web browser just to enjoy it.

GuoTao
14 years ago

Hi Yong,
it’s necessary to considered that compressing directories which are empty in the example of ‘Advance ZIP example – Recursively’.
thank you for sharing,I like the platform.

nagarjuna
14 years ago

can u send me the program for created zip file is automatically send to mail through our gmail……….

Give me reply to my mail [email protected]

Khaled
13 years ago
Reply to  nagarjuna

You can use Java mail to create an e-mail, attach that zip file and send it to that designated address.

abaynew
11 years ago
Reply to  Khaled

hllow dears

how to convert java code into jara files