使用 ProcessBuilder 时 Java 不启动 GZIP 命令

标签 java processbuilder

我确实在尝试此操作的机器上安装了 GZIP。但是当我在 Java 中运行它时,我没有看到正在创建的压缩文件。我正在处理的文件是一个非常大的文件,我宁愿不将其读入内存。以下是我为此目的编写的代码。我的直觉是它与重定向有关。

try {
    ProcessBuilder builder = new ProcessBuilder("gzip", "-9", "<", filename, ">", zippedFilename);
    builder.start();
} catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

最佳答案

首先,值得注意的是,您可以通过避免外部进程并使用 Java 进行压缩来使这一过程变得更容易:

Path input = Paths.get(filename);
Path zipped = Paths.get(zippedFilename);

try (OutputStream out = new GZIPOutputStream(
    new BufferedOutputStream(
        Files.newOutputStream(zipped)))) {

    Files.copy(input, out);
}

这还有一个额外的优势,那就是完全跨平台。不需要/usr/bin/gzip,不需要 Windows 上的 Unix 工具。它不会实现-9选项,但我会检查该选项实际上获得了多少额外压缩,并权衡是否值得拥有一个不太可移植的程序。

对于其他命令(或者如果 -9 非常重要),ProcessBuilder 命令无法使用 < 进行输入和输出重定向。和> ,出于同样的原因,C 程序无法通过如下调用完成重定向:

/* Does not work. */
execl("/usr/bin/gzip", "gzip", "-9", "<", filename, ">", zippedFilename, (char *)NULL);

当您在 shell 中运行命令(如 bash)时,shell 会拦截 <> ,从命令中剥离它们及其后续参数,并在没有它们的情况下调用实际程序。因此,输入:

gzip -9 < filename > filename.gz

实际上会导致 shell 运行 gzip只有一个参数:-9 。然后 shell 从 filename 读取并将其传递给 gzip 程序进程的标准输入描述符。同样,shell 从同一 gzip 程序调用捕获标准输出,并将其写入 filename.gz .

当这种情况发生时,gzip 进程不知道它的输入来自哪里,或者它的输出要去哪里。它只是从自己的标准输入中读取并写入其标准输出。

当您直接调用程序时,您将绕过 shell,因此无需对 < 进行特殊处理。和> 。这意味着您当前的 ProcessBuilder 命令相当于以下 Unix 命令:

gzip -9 '<' filename '>' filename.gz

这意味着您正在使用一个选项和四个文件参数调用 gzip,这会导致 gzip 首先查找名称为一个字符长的文件,即字面上名为 < 的文件。 ,然后将其压缩版本写入 <.gz 。然后,它将对名为 filename 的文件执行相同的操作。 ,然后是一个名为 > 的文件,然后是一个名为 filename.gz 的文件.

因此,如您所见,Unix 命令对重定向一无所知。 <>字符不能直接传递给它们。

但是,您可以使用 ProcessBuilder 模拟重定向:

ProcessBuilder builder = new ProcessBuilder("gzip", "-9");
builder.inheritIO();
builder.redirectInput(new File(filename));
builder.redirectOutput(new File(zippedFilename));

Process process = builder.start();

调用inheritIO()将导致外部进程的标准错误(即任何错误消息)出现在Java程序的标准错误上。如果没有这个,你就无法知道程序失败的原因。 (如果我们没有重定向它们,它会对标准输入和标准输出执行相同的操作。)

关于使用 ProcessBuilder 时 Java 不启动 GZIP 命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52747069/

相关文章:

Java Nashorn 从 Javascript 运行 Java 函数

java - 是否可以使用 ProcessBuilder 运行外部 .class 文件?

java - ProcessBuilder 在 Mac 上给出 "No such file or directory"而 Runtime().exec() 工作正常

java - 在保留其余部分的同时翻转一个字节中的一位的正确方法是什么?

java - 单击选项卡时如何开始新 Activity ?

java - 查找 char [ ] [ ] 内的字符串

java - Python 脚本未在 Java 中输出

java - 包含 & 符号的公式中存在词汇错误

java - 如何使用 Java ProcessBuilder 自动执行命令行脚本

java - 如何使用 Runtime.getRuntime().exec 调用带有文件的 sh shell?