Catalin Vladu
Catalin Vladu

Reputation: 389

Copy a file into a double archive in Java (a zip file which is in another zip file)

I have an ear archive, "archive.ear". This archive contains an war file, "archive.war". In this file, I want to replace a file, "/myFile.properties" with a new one, which exists on disk.

The content of the new file is saved in a java.io.File object, named "file". I saved the output stream from "/myFile.properties" from the archive in a java.io.OutputStream object. And after that, I tried to use

org.apache.commons.io.FileUtils.copy(File input, OutputStream output)

The current code is:

// Java method from extracting the output stream
public OutputStream getOutputStream(OutputStream out, String entry) throws IOException {
    ZipOutputStream zos = new ZipOutputStream(out);
    ZipEntry zipEntry = new ZipEntry(entry);
    while (zipEntry != null) {
        if (zipEntry.toString().equals(entry)) {
            return zos;
        }
    }
    throw new IllegalStateException("No entry '" + entry + "' found");
}

// copy the file content to output stream
// extract output stream "archive.war" from "archive.ear"
OutputStream warOs = zu.getOutputStream(new FileOutputStream("archive.ear"), "archive.war");

// extract output stream "<path>/myFile.properties" from "archive.war"
OutputStream myFileOutput = zu.getOutputStream(warOs, "<path>/myFile.properties" );  

FileUtils.copyFile(file, myFileOutput);

I also tried to use, insted of copyFile():

myFileOutput.write(getBytesFromFile(file));

The method "getBytesFromFile()" returns an array of byte from a file object.

When I open the war archive, I expect "myFile.properties" to have the new content, which is in the java object "file". This file has the right content. The result is a ZipException:

Exception in thread "main" java.util.zip.ZipException: no current ZIP entry
       at java.util.zip.ZipOutputStream.write(Unknown Source)
       at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2315)
       at org.apache.commons.io.IOUtils.copy(IOUtils.java:2270)
       at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2291)
       at org.apache.commons.io.FileUtils.copyFile(FileUtils.java:1094)
       at main.Main.main(Main.java:69)

Upvotes: 0

Views: 513

Answers (1)

Sascha
Sascha

Reputation: 1343

You can't (easily) manipulate the existing zip file with Java. You will have to do this in a roundabout way.

  1. Open the current "archive.ear" as ZipInputStream.
  2. Open a new "archive.ear.new" as ZipOutputStream.
  3. Transfer all ZipEntries from 1. to 2.
    1. When you come to your entry "archive.war"
    2. Open a new ZipInputStream for it
    3. Open a new ZipOutputStream for the entry for 2.
    4. Transfer all of the ZipEntries except your "myFile.properties"
    5. Transfer the content of "myFile.properties" for the entry
    6. Flush your ZipOutputStream, close the entry
  4. Rename the new file to the old file

Upvotes: 1

Related Questions