tags:

views:

1199

answers:

3

I have a zip file containing a folder structure like

  • main-folder/
    • subFolder1/
    • subFolder2/
    • subFolder3/
      • file3.1
      • file3.2

I would like to rename folder main-folder to let's say versionXY inside that very zip file using Java.

Is there a simpler way than extracting the whole zip file and recreating a new one using the new folder names?

+2  A: 

I think you'll be able to find help for this task using the Commons Compress, especially ZipArchiveEntry

Valentin Rocher
+3  A: 

Zip is an archive format, so mutating generally involves rewriting the file.

Some particular features of zip also get in the way (zip is full of "features"). As well as the central directory at the end of the archive, each component file is preceded by its file name. Zip doesn't have a concept of directories - file names are just strings that happen to include "/" characters (and substrings such as "../".

So, you really need to copy the file using ZipInputStream and ZipOutputStream, renaming as you go. If you really wanted to you could rewrite the file in place doing your own buffering. The process does cause the contents to be recompressed as the standard API has no means of obtaining the data in compressed form.

Tom Hawtin - tackline
A: 

I know you asked about Java but just for archival purposes I thought I would contribute a note about .NET.

DotNetZip is a .NET library for zip files that allows renaming of entries. As Tom Hawtin's reply states, directories are not first-class entities in the zip file metadata, and as a result, no zip libraries that I know of expose a "rename directory" verb. But some libraries allow you to rename all the entries that have names that indicate a particular directory, which gives you the result you want.

In DotNetZip, it would look like this:

 var regex = new Regex("/OldDirName/.*$");
 int renameCount= 0;
 using (ZipFile zip = ZipFile.Read(ExistingZipFile))
 {
    foreach (ZipEntry e in zip)
    {
        if (regex.IsMatch(e.FileName))
        {
            // rename here
            e.FileName = e.FileName.Replace("/OldDirName/", "/NewDirName/");
            renameCount++;
        }
    }
    if (renameCount > 0)
    {
        zip.Comment = String.Format("This archive has been modified. {0} entries have been renamed.", renameCount);
        // any changes to the entries are made permanent by Save()
        zip.Save();  // could also save to a new zip file here
    }
 }

You can also add or remove entries, inside the using clause.

If you save to the same file, then DotNetZip rewrites only the changed metadata - the entry headers and the central directory records for renamed entries, which saves time with large archives. If you save to a new file or stream, then all of the zip data gets written.

Cheeso
@Cheeso: The question was about Java library. We can't use your snippet.
dma_k
I know. I started the answer by saying that. I only wanted to put it there, in case someone else did a search for "rename" and "zip" and wasn't limited by Java.
Cheeso