6

I am using below java, but when it zips, it creates a directory and zips all contents inside that directory. For ex. if I have a folder named 'Directory' and I want to zip the content to a Zipped file, inside the zipped file it creates a folder testZip and have files inside that. I need all files inside the zipped file, not inside a parent directory. Please help. or suggest if there is any other way.

package folderZip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

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

public class ZipFolder {
    public ZipFolder() {  
    }  


    public static void main(String[] args) throws Exception {
        ZipFolder obj = new ZipFolder();
        obj.zipFolder("C:\\Drive\\temp\\testZip","C:\\Drive\\temp\\FolderZiper.zip");       
    }


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

    }

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

    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);
            }
        }
    }
}
Vivek Vishal
  • 83
  • 2
  • 7
  • Basically, if I understand your problem, you need to strip off the "source" folder name from the desired zip entry name. Something like [this example](https://stackoverflow.com/questions/28732118/java-zip-file-with-non-static-filename/28732297#28732297) and [this example](https://stackoverflow.com/questions/16381281/creating-folders-in-a-zip-folder-in-java/16381391#16381391) and [this example](https://stackoverflow.com/questions/30183634/how-to-zip-files-and-folders-in-java/30184644#30184644) – MadProgrammer Aug 14 '18 at 03:59
  • Try this: The current folder is "testing" and create a sub-folder called "testfolder". The testfolder has multiple files and one of them is "user-guide.pdf". The program should be able to create a ZIP folder with only one entry user-guide.pdf - the output zip file "MyZip" will have just one file user-guide.pdf. The output zip file is created in a folder of your choice - testing or testfolder. If you are able to do that, you can apply the same logic to the application you are trying. Also, one can use `Files.walkFileTree` and `FileVisitor` APIs to walk the file tree and zip the contents. – prasad_ Aug 14 '18 at 04:15

3 Answers3

8

So, if I understand correctly, what you want is, instead of the target folder appearing in the Zip file, all the files within it should start at "/" in the Zip file.

For example, if you had

FolderToZip/
    TestFile1.txt
    TestFile2.txt
    TestFile3.txt
    SomeSubFolder/
        TestFile4.txt
        TestFile5.txt
        TestFile6.txt

The contents of the Zip file should contain

TestFile1.txt
TestFile2.txt
TestFile3.txt
SomeSubFolder/
    TestFile4.txt
    TestFile5.txt
    TestFile6.txt

To do this, you need to keep a reference to the "start" folder and strip it's path off the files you are adding, to create the ZipEntry.

For simplicity, I changed your code to support File instead of String, it just makes the whole thing a lot less messy.

But the magic appears here...

FileInputStream in = new FileInputStream(srcFile);
String name = srcFile.getPath();
name = name.replace(rootPath.getPath(), "");
System.out.println("Zip " + srcFile + "\n to " + name);
zip.putNextEntry(new ZipEntry(name));

rootPath is the initial folder (C:\\Drive\\temp\\testZip" in your example), srcFile is the file to be added.

Runnable example...

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


public class ZipFolder {

    public ZipFolder() {
    }

    public static void main(String[] args) throws Exception {
        ZipFolder obj = new ZipFolder();
        obj.zipFolder(new File("/Users/shanewhitehead/exports"),
                new File("FolderZiper.zip"));
    }

    public void zipFolder(File srcFolder, File destZipFile) throws Exception {
        try (FileOutputStream fileWriter = new FileOutputStream(destZipFile);
                ZipOutputStream zip = new ZipOutputStream(fileWriter)) {

            addFolderToZip(srcFolder, srcFolder, zip);
        }
    }

    private void addFileToZip(File rootPath, File srcFile, ZipOutputStream zip) throws Exception {

        if (srcFile.isDirectory()) {
            addFolderToZip(rootPath, srcFile, zip);
        } else {
            byte[] buf = new byte[1024];
            int len;
            try (FileInputStream in = new FileInputStream(srcFile)) {
                String name = srcFile.getPath();
                name = name.replace(rootPath.getPath(), "");
                System.out.println("Zip " + srcFile + "\n to " + name);
                zip.putNextEntry(new ZipEntry(name));
                while ((len = in.read(buf)) > 0) {
                    zip.write(buf, 0, len);
                }
            }
        }
    }

    private void addFolderToZip(File rootPath, File srcFolder, ZipOutputStream zip) throws Exception {
        for (File fileName : srcFolder.listFiles()) {
            addFileToZip(rootPath, fileName, zip);
        }
    }
}

I also cleaned up your resource management, using try-with-resources

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks a lot, you saved my day :) I just made one small modification, in the zip file one '\' was getting added in windows so I added : name = name.replace(rootPath.getPath(), ""); name = name.substring(1); to remove the first '\'. not sure if in linux it was already working fine, will test – Vivek Vishal Aug 14 '18 at 07:35
0

What about use this lib Zeroturnaround Zip library
Then you will zip your folder just a one line:

ZipUtil.pack(new File("D:\\sourceFolder\\"), new File("D:\\generatedZipFile.zip"));
Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
0

You can call like this.

zipFoldersAndFiles(Paths.get(sourcesPath), Paths.get(exportLocationPath));

Declare the method.

private void zipFoldersAndFiles(Path sourcesFolderPath, Path zipPath){

    new Thread(() -> {

        try {
            ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath.toFile()));

            Files.walkFileTree(sourcesFolderPath, new SimpleFileVisitor<Path>() {

                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {

                    zipOutputStream.putNextEntry(new ZipEntry(sourcesFolderPath.relativize(file).toString()));
                    zipOutputStream.setLevel(ZipOutputStream.STORED);
                    Files.copy(file, zipOutputStream);
                    zipOutputStream.closeEntry();
                    return FileVisitResult.CONTINUE;
                }
            });

            zipOutputStream.close();
        }
        catch (Exception e){
            System.out.println("error");
        }
    }).start();
}
Nur Alam
  • 192
  • 2
  • 8