Modifying a text file in a ZIP archive in Java

Prabhakar picture Prabhakar · Jul 16, 2012 · Viewed 17.9k times · Source

My use case requires me to open a txt file, say abc.txt which is inside a zip archive which contains key-value pairs in the form

key1=value1

key2=value2

.. and so on where each key-value pair is in a new line. I have to change one value corresponding to a certain key and put the text file back in a new copy of the archive. How do I do this in java?

My attempt so far:

    ZipFile zipFile = new ZipFile("test.zip");
    final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("out.zip"));
    for(Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
        ZipEntry entryIn = (ZipEntry) e.nextElement();
        if(!entryIn.getName().equalsIgnoreCase("abc.txt")){
            zos.putNextEntry(entryIn);
            InputStream is = zipFile.getInputStream(entryIn);
            byte [] buf = new byte[1024];
            int len;
            while((len = (is.read(buf))) > 0) {            
                zos.write(buf, 0, len);
            }
        }
        else{
            // I'm not sure what to do here
            // Tried a few things and the file gets corrupt
        }
        zos.closeEntry();
    }
    zos.close();

Answer

Alex Lipov picture Alex Lipov · May 7, 2017

Java 7 introduced a much simpler way for doing zip archive manipulations - FileSystems API, which allows to access contents of a file as a file system.

Besides much more straightforward API, it is doing the modification in-place and doesn't require to rewrite other (irrelevant) files in a zip archive (as done in the accepted answer).

Here's sample code that solves OP's use case:

import java.io.*;
import java.nio.file.*;

public static void main(String[] args) throws IOException {
    modifyTextFileInZip("test.zip");
}

static void modifyTextFileInZip(String zipPath) throws IOException {
    Path zipFilePath = Paths.get(zipPath);
    try (FileSystem fs = FileSystems.newFileSystem(zipFilePath, null)) {
        Path source = fs.getPath("/abc.txt");
        Path temp = fs.getPath("/___abc___.txt");
        if (Files.exists(temp)) {
            throw new IOException("temp file exists, generate another name");
        }
        Files.move(source, temp);
        streamCopy(temp, source);
        Files.delete(temp);
    }
}

static void streamCopy(Path src, Path dst) throws IOException {
    try (BufferedReader br = new BufferedReader(
            new InputStreamReader(Files.newInputStream(src)));
         BufferedWriter bw = new BufferedWriter(
            new OutputStreamWriter(Files.newOutputStream(dst)))) {

        String line;
        while ((line = br.readLine()) != null) {
            line = line.replace("key1=value1", "key1=value2");
            bw.write(line);
            bw.newLine();
        }
    }
}

For more zip archive manipulation examples, see demo/nio/zipfs/Demo.java sample which you can download here (look for JDK 8 Demos and Samples).