I am trying to put files from a folder inside a zip file in the following structure:
Folder structure:
myFolder
 |-file1.txt
 |-file2.txt
 |-folder172
    |-file817.txt
    |-file818.txt
 ...
Supposed structure inside ZipFile:
file1.txt
file2.txt
folder172
 |-file817.txt
 |-file818.txt
This is my code:
public static void writeZip(String path) throws IOException{
    FileOutputStream fos = new FileOutputStream(path+File.separator+"atest.zip");
    ZipOutputStream zos = new ZipOutputStream(fos);
    try {
        Files.walk(Paths.get(path)).filter(Files::isRegularFile).forEach((string) -> addToZipFile(string.toString(),zos));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    zos.close();
    fos.close();
}
public static void addToZipFile(String fileName, ZipOutputStream zos) throws IOException {
    System.out.println("Writing '" + fileName + "' to zip file");
    File file = new File(fileName);
    FileInputStream fis = null;
    fis = new FileInputStream(file);
    ZipEntry zipEntry = new ZipEntry(fileName);
    zos.putNextEntry(zipEntry);
    byte[] bytes = new byte[1024];
    int length;
    while ((length = fis.read(bytes)) >= 0) {
        zos.write(bytes, 0, length);
    }
    zos.closeEntry();
    fis.close();
}
The problem is now, when i call writeZip("/home/arthur/.grutil/");, i get the following structure in the zip-file:
home
 |-arthur
    |-.grutil
       |-file1.txt
       |-file2.txt
       |-folder172
          |-file817.txt
          |-file818.txt
   ...
How do i need to change my code to get the supposed structure (as described above) and not the structure with the full path '/home/arthur/.grutil/ ...'?
Whilst this can be done with the ancient ZipOutputStream I would recommend against it.
It is much more intuitive to think about a Zip archive as a compressed filesystem inside a file, than a stream of bytes. For this reason, Java provides the ZipFileSystem.
So all you need to do is open the Zip as a FileSystem and then manually copy files across.
There are a couple of gotchas:
relativize across different filesystems (reasons should be obvious) so this you need to do yourself.Here are a couple of simple methods that will do exactly that:
/**
 * This creates a Zip file at the location specified by zip
 * containing the full directory tree rooted at contents
 *
 * @param zip      the zip file, this must not exist
 * @param contents the root of the directory tree to copy
 * @throws IOException, specific exceptions thrown for specific errors
 */
public static void createZip(final Path zip, final Path contents) throws IOException {
    if (Files.exists(zip)) {
        throw new FileAlreadyExistsException(zip.toString());
    }
    if (!Files.exists(contents)) {
        throw new FileNotFoundException("The location to zip must exist");
    }
    final Map<String, String> env = new HashMap<>();
    //creates a new Zip file rather than attempting to read an existing one
    env.put("create", "true");
    // locate file system by using the syntax
    // defined in java.net.JarURLConnection
    final URI uri = URI.create("jar:file:/" + zip.toString().replace("\\", "/"));
    try (final FileSystem zipFileSystem = FileSystems.newFileSystem(uri, env);
         final Stream<Path> files = Files.walk(contents)) {
        final Path root = zipFileSystem.getPath("/");
        files.forEach(file -> {
            try {
                copyToZip(root, contents, file);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }
}
/**
 * Copy a specific file/folder to the zip archive
 * If the file is a folder, create the folder. Otherwise copy the file
 *
 * @param root     the root of the zip archive
 * @param contents the root of the directory tree being copied, for relativization
 * @param file     the specific file/folder to copy
 */
private static void copyToZip(final Path root, final Path contents, final Path file) throws IOException {
    final Path to = root.resolve(contents.relativize(file).toString());
    if (Files.isDirectory(file)) {
        Files.createDirectories(to);
    } else {
        Files.copy(file, to);
    }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With