0

Regarding the following post: Appending files to a zip file with Java

I'm trying to unzip huge zip file , about 5GB , the best time it took me is about 30 min cause my bottleneck is I/O writes , so I tried to change the approach and make modification inside ZIP itself.

My scenarios are very simple: add few file/files/folder , the code works perfect on small zip files , but on large are not working.

I've tried plenty of combinations...attached some attempts:

1st :

   public static void main(String[] args) {
        String zip = "/Users/xxx/Documents/test/before.zip";

        Map<String, String> env = new HashMap<>();
        env.put("create", "true");
        Path path = Paths.get(zip);
        URI uri = URI.create("jar:" + path.toUri());
        try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
            Path toAdd = Paths.get("/Users/xxx/Documents/test/append.txt");
                Path directory = fs.getPath("/some/directory");

                //create if not exists
                Files.createDirectories(directory);

                //add to dir new file
                Files.copy(toAdd, directory.resolve("replaced.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

But I got:

java.lang.OutOfMemoryError: Java heap space

at sun.util.calendar.Gregorian.newCalendarDate(Gregorian.java:85)
at sun.util.calendar.Gregorian.newCalendarDate(Gregorian.java:37)
at java.util.Date.<init>(Date.java:254)
at com.sun.nio.zipfs.ZipUtils.dosToJavaTime(ZipUtils.java:122)
at com.sun.nio.zipfs.ZipFileSystem$Entry.cen(ZipFileSystem.java:1884)
at com.sun.nio.zipfs.ZipFileSystem$Entry.readCEN(ZipFileSystem.java:1871)
at com.sun.nio.zipfs.ZipFileSystem.sync(ZipFileSystem.java:1257)
at com.sun.nio.zipfs.ZipFileSystem.close(ZipFileSystem.java:277)
at TrueZi.AAA.append200Files7KBExistingFolder(AAA.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:71)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.junit.runner.JUnitCore.run(JUnitCore.java:121)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

or

java.lang.OutOfMemoryError: Java heap space

    at com.sun.nio.zipfs.ZipFileSystem$Entry.readCEN(ZipFileSystem.java:1871)
    at com.sun.nio.zipfs.ZipFileSystem.sync(ZipFileSystem.java:1257)
    at com.sun.nio.zipfs.ZipFileSystem.close(ZipFileSystem.java:277)
    at TrueZi.AAA.test(AAA.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
    at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
    at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
    at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
    at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
    at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:71)
    at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
    at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
    at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)...

is it could be this ?

https://community.oracle.com/thread/4123064

Another try is as one saying (rewrite the zip into other zip name and append the new file , but it takes me average same time as unzip):

ZipInputStream original = new ZipInputStream(new BufferedInputStream(new FileInputStream("/Users/xxx/Documents/test/original.zip")));
        ZipOutputStream append = new ZipOutputStream(new FileOutputStream("/Users/xxx/Documents/test/rename.zip"));
        ZipEntry entry;
        while ((entry = original.getNextEntry()) != null) {
            append.putNextEntry(entry);
            if (!entry.isDirectory()) {
                IOUtils.copy(original, append);
            }
            append.closeEntry();
        }

        File f = new File(appended);
        try (FileInputStream inputStream = new FileInputStream(f)) {
            append.putNextEntry(new ZipEntry(f.getName()));
            byte[] readBuffer = new byte[4096];
            int amountRead;

            while ((amountRead = inputStream.read(readBuffer)) > 0) {
                append.write(readBuffer, 0, amountRead);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    // close
    original.close();
    append.close();

I'm wondering if there is other any option neither using FileSystem not rewrite all huge zip to other....??

VitalyT
  • 1,671
  • 3
  • 21
  • 49
  • 1
    Have you tried increasing your heap size? (-Xmx*G - where * is the amount of Gigabytes to allocate) – maio290 Aug 30 '18 at 14:38
  • @ maio290 , I don't have so much memory to dedicate to this zip , as my server using other running processing that taking memory....P.S - unzip works fine via JAVA but it is not efficient – VitalyT Aug 31 '18 at 17:18

1 Answers1

0

please make use of

env.put("useTempFile", Boolean.TRUE);

as described here. then you will not receive OutOfMemory errors

guleryuz
  • 2,714
  • 1
  • 15
  • 19
  • @ guleryuz , thanks , I've tried , it doesn't work :( , I'm wondering if these are only possibilities for insert new entry , either use NIO FileSystem or rewrite all huge zip to other and then append the leftover ? – VitalyT Aug 31 '18 at 17:16
  • On a typical server there is rarely that huge space in /tmp (on linux, this is the tmp directory for every application). You have to combine this answer with the -Djava.io.tmpdir=/path/to/tmpdir JVM argument. This tmpdir can be anywhere, but there must be enough free space for your program. – m4gic Sep 12 '18 at 15:18