16

I've successfully modified the contents of a (existing) zip file using the FileSystem provided by java 7, but when I tried to create a NEW zip file by this method it fails, with the error message that says: "zip END header not found", it is logical because of the way I'm doing it, first I create the file (Files.createFile) which is a completely empty file, and then I try to access to its file system , and since the file is empty its impossible to find any header inside the zip, my question is is there any way to create a new zip file completely empty using this method?; the hack that I've considered is adding an empty new ZipEntry to a the zip file and then using that new empty file to crate the file system based on it, but i really want to think that the guys of oracle implemented a better (easier) way to do this with nio and the filesystems...

this is my code (the error appears when creating the file system):

if (!zipLocation.toFile().exists()) {
        if (creatingFile) {
            Files.createFile(zipLocation);
        }else {
            return false;
        }
    } else if (zipLocation.toFile().exists() && !replacing) {
        return false;
    } 
    final FileSystem fs = FileSystems.newFileSystem(zipLocation, null);
.
.
.

zipLocation is a Path creatingFile is a boolean

ANSWER: in my particular case the answer given didn't work appropriately because of the spaces in the path, therefore i have to do it the way i didn't want to:

Files.createFile(zipLocation);
ZipOutputStream out = new ZipOutputStream(
    new FileOutputStream(zipLocation.toFile()));
out.putNextEntry(new ZipEntry(""));
out.closeEntry();
out.close();

it does not mean that the given answer is wrong, it just didn't work for my particular case

tshepang
  • 12,111
  • 21
  • 91
  • 136
Ordiel
  • 2,442
  • 3
  • 36
  • 52

1 Answers1

25

As described in The Oracle Site:

public static void createZip(Path zipLocation, Path toBeAdded, String internalPath) throws Throwable {
    Map<String, String> env = new HashMap<String, String>();
    // check if file exists
    env.put("create", String.valueOf(Files.notExists(zipLocation)));
    // use a Zip filesystem URI
    URI fileUri = zipLocation.toUri(); // here
    URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
    System.out.println(zipUri);
    // URI uri = URI.create("jar:file:"+zipLocation); // here creates the
    // zip
    // try with resource
    try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {
        // Create internal path in the zipfs
        Path internalTargetPath = zipfs.getPath(internalPath);
        // Create parent directory
        Files.createDirectories(internalTargetPath.getParent());
        // copy a file into the zip file
        Files.copy(toBeAdded, internalTargetPath, StandardCopyOption.REPLACE_EXISTING);
    }
}

public static void main(String[] args) throws Throwable {
    Path zipLocation = FileSystems.getDefault().getPath("a.zip").toAbsolutePath();
    Path toBeAdded = FileSystems.getDefault().getPath("a.txt").toAbsolutePath();
    createZip(zipLocation, toBeAdded, "aa/aa.txt");
}
Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137
Carlo Pellegrini
  • 5,656
  • 40
  • 45
  • 1
    Almost there, but I'm having troubles with the URI part, (unfortunately) I'm working in windows, and it is giving me errors while creating the URI whether the ":", the "\" or the space, any sugestion? – Ordiel Feb 06 '13 at 17:11
  • @Ordiel Edited the answer. turns out it was incorrect. Should deal with windows too. – Carlo Pellegrini Feb 06 '13 at 17:44
  • 2
    it fails if there is a space in the path to the zip... :/ what do you think it might be? – Ordiel Feb 06 '13 at 18:20
  • 1
    Sadly, seems a bug on the jre. See http://stackoverflow.com/questions/9873845/java-7-zip-file-system-provider-doesnt-seem-to-accept-spaces-in-uri for an in-depdth examination – Carlo Pellegrini Feb 06 '13 at 20:38
  • I had to do some hacking with a URI and it's name: FileSystems.newFileSystem(URI.create("jar:file:"+Paths.get(zipFilePath).toUri().getPath()), env, null) – Martin Stein May 20 '13 at 23:32
  • Has anyone had any problems with this approach using JDK 11? I'm failing to get a path from the zip file system because ZipPath is package private to the jdk.nio.zipfs package... I get: jdk.nio.zipfs.ZipFileSystem (in module jdk.zipfs) because module jdk.zipfs does not export jdk.nio.zipfs to unnamed module @75de29c0 – spot35 Jul 30 '20 at 12:49