1

I am trying to unzip some zip file, it has about 65 megs. Code snippets below:

This method actually unzips a file:

public synchronized void execute(Path zipFile) {
    final ProcessBuilder builder = new ProcessBuilder("/bin/unzip",zipFile.toAbsolutePath().toString(), "-d", dir.toAbsolutePath().toString());
    FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
        @Override public Integer call() {
            try {
                System.out.println("started and waiting");
                int status = builder.start().waitFor();
                System.out.println("status: " + status);
                return status;
            } catch (InterruptedException e) {
            } catch (IOException e) {
            }
            return 0;
        }
    });

    List<FutureTask<Integer>> tasks = new ArrayList<FutureTask<Integer>>();
    tasks.add(task);
    System.out.println("task added");
    ExecutorService executor = Executors.newCachedThreadPool();
    for (FutureTask<Integer> t : tasks) {
        executor.submit(t);
        System.out.println("submitted");
    }
    executor.shutdown();
    System.out.println("shutdown");
}

That executor / future stuff is there just to be sure I do it properly. This method is called in the class Finder, which finds zip file in the directory and tries to unzip it. It is based on this code http://docs.oracle.com/javase/tutorial/essential/io/walk.html

So to be concrete:

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    if (find(file)) {
        synchronized(Finder.class) {
            executor.execute(file);
        }
    }
    return CONTINUE;
}

Now the problem. It is really funny. Whenever I extract something by this code, the zip file actually gets unzipped but ONLY some directories are unzipped and others are not. For example I have a zip file with directories temp foo and bar but after unzipping, there are only e.g temp and foo directories and bar is not extracted.

Output from this is:

task added
submitted
started and waiting
shutdown

Why there is no "status = something" output?

I can't understand why it is so. When I unzip it manually, it gets unzipped properly.

// EDIT

this did the trick

@Override
public synchronized void execute(String file, String dest) {
    ProcessBuilder pb = new ProcessBuilder("/bin/unzip","-qq", file, "-d", dest);
    pb.redirectErrorStream(true);

    try {
        Process p = pb.start();
        InputStream is = p.getInputStream();
        InputStreamReader r = new InputStreamReader(is);
        BufferedReader in = new BufferedReader(r);
        String line;
        while ((line = in.readLine()) != null) {
            // because of the -qq option, it does actually write out nothing
            System.out.println(line);
        }
    } catch (IOException ex) {
        System.err.println(ex.getMessage());
    }
}
user207421
  • 305,947
  • 44
  • 307
  • 483
stewenson
  • 1,282
  • 3
  • 15
  • 34
  • `shutdown` does not block until the executor terminates. That is `awaitTermination`. By the way, you can just do `Collections.singleton(task)` – obataku Sep 29 '12 at 15:37
  • By the way, share a single executor... there's no point in creating a new one for each unzip operation. – obataku Sep 29 '12 at 15:38
  • thanks for tips . it does not help, the result is the same, i added executor.awaitTermination(1, TimeUnit.HOURS); right after the executor.shutdown but there are extracted only 2 dirs and nothing happens at all. I had to kill it manually :/ – stewenson Sep 29 '12 at 15:48
  • `ProcessBuilder.waitFor` or some other code is indefinitely blocking. – obataku Sep 29 '12 at 15:50
  • yes, deleting waitFor() did the trick with quitting the program but the zip file is still only partially extracted ... it looks like it does unzip something but the process (like an activity) of the unzipping is stopped before all files are extracted ... – stewenson Sep 29 '12 at 15:57

2 Answers2

2

The unzip command prints the details of the files it is unzipping to its standard output, so you need to read this in your Java program (via Process.getInputStream). If you don't read the output in a timely fashion the process may block once its buffer gets full - this is spelled out in the javadoc of Process.

I recommend you call builder.redirectErrorStream(true) and then ensure you read all the data from the process stream. You may also benefit from adding a -qq argument to the unzip call, to minimise the amount of output it creates in the first place.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
0

I think problem is because of timeout constraint.

You can try below code to execute process

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);

I think it will work.

shekhar
  • 1
  • 1
  • Is the Runtime api same as the ProcessBuilder api from the functional point of view? E.g. while doing some processing stuff very rarely, can I use your solution as well? Does it have some significant differences? – stewenson Sep 29 '12 at 18:48
  • yes both are giving same functionality. Only difference is that Runtime api gets string as argument and processbuilder takes array of string as argument. – shekhar Sep 30 '12 at 11:21