【问题标题】:Java process - unable to unzip zip fileJava 进程 - 无法解压缩 zip 文件
【发布时间】:2012-09-29 15:26:56
【问题描述】:

我正在尝试解压缩一些 zip 文件,它大约有 65 兆。代码如下:sn-ps:

这个方法实际上解压了一个文件:

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

那个执行者/未来的东西只是为了确保我做得正确。这个方法在类 Finder 中调用,它在目录中找到 zip 文件并尝试解压缩它。它基于此代码http://docs.oracle.com/javase/tutorial/essential/io/walk.html

具体来说:

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

现在的问题。这真的很有趣。每当我通过此代码提取某些内容时,zip 文件实际上会被解压缩,但只有一些目录被解压缩,而其他目录则没有。例如,我有一个包含 temp foo 和 bar 目录的 zip 文件,但解压缩后,只有例如 temp 和 foo 目录,并且 bar 没有被提取。

输出如下:

task added
submitted
started and waiting
shutdown

为什么没有“status = something”输出?

我不明白为什么会这样。当我手动解压缩时,它会正确解压缩。

// 编辑

成功了

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

【问题讨论】:

  • shutdown 在执行程序终止之前不会阻塞。那是awaitTermination。顺便说一句,你可以做Collections.singleton(task)
  • 顺便说一下,共享一个执行器...为每个解压缩操作创建一个新的执行器是没有意义的。
  • 感谢您的提示。它没有帮助,结果是一样的,我添加了 executor.awaitTermination(1, TimeUnit.HOURS);在 executor.shutdown 之后,但只提取了 2 个目录,根本没有任何反应。我不得不手动杀死它:/
  • ProcessBuilder.waitFor 或其他一些代码被无限期阻塞。
  • 是的,删除 waitFor() 完成了退出程序的技巧,但 zip 文件仍然只是部分解压缩......看起来它确实解压缩了一些东西,但过程(如活动)在提取所有文件之前停止解压缩...

标签: java multithreading process zip


【解决方案1】:

unzip 命令将解压缩文件的详细信息打印到其标准输出,因此您需要在 Java 程序中阅读此内容(通过Process.getInputStream)。如果您没有及时读取输出,则进程可能会在其缓冲区已满时阻塞 - 这在 Process 的 javadoc 中有详细说明。

我建议您致电builder.redirectErrorStream(true),然后确保您从流程流中读取所有数据。您还可能受益于在 unzip 调用中添加 -qq 参数,以最大限度地减少它首先创建的输出量。

【讨论】:

    【解决方案2】:

    我认为问题是由于超时限制。

    你可以试试下面的代码来执行流程

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

    我认为它会起作用。

    【讨论】:

    • 从功能上看,Runtime api 和 ProcessBuilder api 一样吗?例如。虽然很少做一些处理工作,但我也可以使用您的解决方案吗?它有一些显着差异吗?
    • 是的,两者都提供相同的功能。唯一的区别是 Runtime api 将字符串作为参数,而 processbuilder 将字符串数组作为参数。
    最近更新 更多